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-1831: Action overlay #141

Merged
merged 4 commits into from
Nov 29, 2024
Merged

BA-1831: Action overlay #141

merged 4 commits into from
Nov 29, 2024

Conversation

pt-tsl
Copy link
Contributor

@pt-tsl pt-tsl commented Nov 28, 2024

Acceptance Criteria
Context
This story will handle the creation of the Chat List Card overlay.

Business Rules - Chat Room Overlay - 5 points
As a user, I want an option to appear on chat cards that allows me to archive, mark as unread and delete chat rooms so that I can easily identify and select chats to archive without extra steps.

When I hover my mouse over a chat list card in my Active Chat list, an overlay with an archive, mark as unread and delete appears on the card.

When I hover over a chat card, the overlay appears within one second to ensure it is quick and responsive.

Buttons are not going to be functional for now.

When I move my mouse away from the chat card, the overlay disappears immediately.

When I hover over a chat card on any device, the overlay appears consistently, regardless of screen size or resolution.

Reuse the component used in comments, that already have the behavior for mobile.

The idea of the story is to take that component and make it reusable so that it can handle the above behaviors.

Document the new component in Storybook

Guardrails

You are not expected to actually build the archive function in this story, only build the overlay behavior.

Current behavior

Expected behavior

Code Snippet

Design Link: https://www.figma.com/design/XRD6wSl1m8Kz6XUcAy5CLp/BaseApp---WEB?node-id=3307-228731&node-type=frame&t=62koKJbgByOTvcDm-0

Approvd
https://app.approvd.io/projects/BA/stories/36467

Summary by CodeRabbit

Release Notes for Version 0.0.21

  • New Features

    • Introduced the ActionsOverlay component for managing actions related to comments and chat rooms, enhancing user interaction.
    • Integrated ActionsOverlay into both CommentItem and ChatRoomItem components for consistent action management.
    • Added new icons: Archive and Unread to the design system.
  • Bug Fixes

    • Streamlined deletion functionality within comments, improving user experience when managing comments.
  • Documentation

    • Updated changelog to reflect the new version and component changes.
    • Added documentation for the ActionsOverlay component in Storybook.
  • Chores

    • Version updated from 0.0.20 to 0.0.21 in the package.json file.

Copy link

changeset-bot bot commented Nov 28, 2024

⚠️ No Changeset found

Latest commit: f2d8eb6

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 Nov 28, 2024

Walkthrough

The changes in this pull request involve the introduction and integration of a new component called ActionsOverlay, which replaces the previously existing CommentOptions component. This new component enhances the functionality of both CommentItem and ChatRoomItem components by providing an overlay for action buttons related to comments. The pull request also includes updates to the type definitions and styled components associated with the new ActionsOverlay, as well as updates to dependencies and the changelog for versioning.

Changes

File Change Summary
packages/components/CHANGELOG.md Updated to include version 0.0.21; renamed CommentOptions to ActionsOverlay.
packages/components/modules/__shared__/ActionsOverlay/index.tsx Introduced ActionsOverlay component with props for managing actions and delete confirmation.
packages/components/modules/__shared__/ActionsOverlay/styled.tsx Added styled components: ActionOverlayContainer and IconButtonContentContainer.
packages/components/modules/__shared__/ActionsOverlay/types.ts Added new types: OverlayAction, LongPressHandler, and interfaces for props.
packages/components/modules/comments/CommentItem/CommentOptions/index.tsx Removed CommentOptions component.
packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx Removed styled components related to CommentOptions.
packages/components/modules/comments/CommentItem/CommentOptions/types.ts Removed CommentOptionsProps interface.
packages/components/modules/comments/CommentItem/index.tsx Updated to use ActionsOverlay instead of CommentOptions, removed long press functionality.
packages/components/modules/comments/CommentItem/types.ts Removed CommentOptionsProps from CommentItemProps interface.
packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx Updated return type to OverlayAction[], removed unused parameters.
packages/components/modules/comments/CommentItem/useCommentOptions/types.ts Removed onLongPressLeave from UseCommentOptionsParams interface.
packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx Added ActionsOverlay to encapsulate chat card functionality.
packages/components/package.json Updated version from 0.0.20 to 0.0.21.
packages/design-system/CHANGELOG.md Updated to include version 0.0.22; added Archive and Unread icons.
packages/design-system/components/icons/ArchiveIcon/index.tsx Introduced ArchiveIcon component.
packages/design-system/components/icons/UnreadIcon/index.tsx Introduced UnreadIcon component.
packages/design-system/components/icons/index.ts Updated exports to include new icons and reinstated previously removed icons.
packages/design-system/package.json Updated version from 0.0.21 to 0.0.22.
packages/wagtail/CHANGELOG.md Updated to include version 1.0.4; updated dependency for @baseapp-frontend/design-system.
packages/wagtail/package.json Updated version from 1.0.3 to 1.0.4.

Possibly related PRs

Suggested reviewers

  • deboracosilveira

🐰 In the meadow, changes bloom,
ActionsOverlay dispels the gloom.
Comments now with ease we share,
A click, a tap, without a care.
With styles and types, all anew,
Hopping forward, we bid adieu! 🐇✨

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/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlayOnButton/index.tsx

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)

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

🧹 Outside diff range and nitpick comments (8)
packages/components/modules/__shared__/ActionsOverlay/styled.tsx (1)

21-27: Consider enhancing mobile responsiveness

The grid layout could be more adaptive for different screen sizes and content lengths:

export const IconButtonContentContainer = styled(Box)(({ theme }) => ({
  alignItems: 'center',
  display: 'grid',
-  gridTemplateColumns: 'minmax(max-content, 24px) 1fr',
+  gridTemplateColumns: 'minmax(24px, max-content) minmax(0, 1fr)',
  gap: theme.spacing(1),
  alignSelf: 'center',
+  [theme.breakpoints.down('sm')]: {
+    gap: theme.spacing(0.5),
+  },
}))

This change:

  • Prevents icon column from growing too large
  • Ensures text content can shrink if needed
  • Adjusts spacing on mobile devices
packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx (1)

22-24: Consider removing or documenting the disabled share action

The share action is disabled and has an empty click handler. If this is intentional, please add a comment explaining why it's kept. Otherwise, consider removing it to reduce technical debt.

-    {
-      disabled: true,
-      icon: <LinkIcon />,
-      label: 'Share Comment',
-      onClick: () => {},
-      hasPermission: true,
-      closeOnClick: true,
-    },
packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx (1)

81-131: Consider adding accessibility improvements

While the card implementation is solid, consider enhancing accessibility:

  1. Add aria-labels for interactive elements
  2. Include appropriate ARIA roles
  3. Consider keyboard navigation support

Example improvements:

 <StyledChatCard
   key={`room-${room.id}`}
   onClick={handleCardClick}
   isCardSelected={isCardSelected}
   showPointer={!!handleClick}
+  role="listitem"
+  aria-label={`Chat room ${roomData.title}`}
+  tabIndex={0}
 >
packages/components/CHANGELOG.md (1)

3-8: Enhance the changelog entry with more details.

While the entry captures the core change, consider expanding it to better reflect the full scope of changes:

 ## 0.0.21

 ### Patch Changes

-Renamed CommentOptions component to ActionsOverlay, and made it reusable. Applied ActionsOverlay on CommentItem and ChatRoom components
+- Renamed CommentOptions component to ActionsOverlay for improved reusability
+- Enhanced ActionsOverlay with hover-triggered behavior and mobile support
+- Integrated ActionsOverlay into CommentItem and ChatRoom components
+- Added Storybook documentation for ActionsOverlay component
packages/components/modules/comments/CommentItem/index.tsx (2)

49-49: Consider keeping plural form for consistency.

The state variable isReplyExpanded might be clearer as isRepliesExpanded since it controls the visibility of multiple replies.

-  const [isReplyExpanded, setIsReplyExpanded] = useState(false)
+  const [isRepliesExpanded, setIsRepliesExpanded] = useState(false)

137-142: Consider making avatar dimensions configurable.

The hardcoded avatar dimensions might affect component reusability across different contexts. Consider making these configurable through props.

+ interface CommentItemProps {
+   avatarSize?: number;
+   // ... other props
+ }

  const CommentItem: FC<CommentItemProps> = ({
+   avatarSize = 40,
    // ... other props
  }) => {
    // ...
    <AvatarWithPlaceholder
-     width={40}
-     height={40}
+     width={avatarSize}
+     height={avatarSize}
      alt={comment.user?.fullName ?? `Comment's user avatar`}
      src={comment.user?.avatar?.url}
    />
packages/components/modules/__shared__/ActionsOverlay/index.tsx (2)

48-50: Update comments to reflect the current component and variables

The comments at lines 48-50 reference comment options's drawer and isLongPressingComment, which seem outdated and may cause confusion. Update the comments to accurately describe the ActionsOverlay component and its state variables.

Apply this diff to update the comments:

- // This is a workaround to prevent the comment options's drawer from closing when the user clicks on the drawer's content.
- // Ideally, we would call setLongPressHandler({ isLongPressingComment: false }) on `onFinished` instead of `onCancel`.
- // But, on mobile google chrome devices, the long press click is being wrongly propagated to the backdrop and closing the comment options's drawer right after it opens.
+ // This is a workaround to prevent the action overlay from closing when the user clicks on the overlay's content.
+ // Ideally, we would call setLongPressHandler({ isLongPressingItem: false }) on `onFinished` instead of `onCancel`.
+ // However, on mobile Google Chrome devices, the long press click is incorrectly propagated to the backdrop, closing the action overlay immediately after it opens.

51-53: Simplify type checking of 'className'

At lines 51-53, the type checking for className can be simplified. Since className is always a string on an HTMLElement, the additional type checking is unnecessary.

Apply this diff to simplify the code:

- const className = (e?.target as HTMLElement)?.className || ''
- const classNameString = typeof className === 'string' ? className : ''
- const isClickOnBackdrop = classNameString.includes('MuiBackdrop')
+ const className = ((e?.target as HTMLElement)?.className) || ''
+ const isClickOnBackdrop = className.includes('MuiBackdrop')
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ef0aef0 and 158e6e27e0f401791950bc2e0eae5335879e1c61.

📒 Files selected for processing (13)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/index.tsx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/styled.tsx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/types.ts (1 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/index.tsx (0 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx (0 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/types.ts (0 hunks)
  • packages/components/modules/comments/CommentItem/index.tsx (4 hunks)
  • packages/components/modules/comments/CommentItem/types.ts (0 hunks)
  • packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx (2 hunks)
  • packages/components/modules/comments/CommentItem/useCommentOptions/types.ts (0 hunks)
  • packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx (3 hunks)
  • packages/components/package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • packages/components/modules/comments/CommentItem/CommentOptions/index.tsx
  • packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx
  • packages/components/modules/comments/CommentItem/CommentOptions/types.ts
  • packages/components/modules/comments/CommentItem/types.ts
  • packages/components/modules/comments/CommentItem/useCommentOptions/types.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/components/package.json
🔇 Additional comments (12)
packages/components/modules/__shared__/ActionsOverlay/styled.tsx (2)

1-4: LGTM! Imports are clean and well-organized.


1-27: Verify hover timing requirements

The PR requirements specify that the overlay should:

  • Appear within 1 second of hovering
  • Disappear immediately when the mouse leaves

Please ensure that the parent component implementing this styled component handles these timing requirements correctly.

packages/components/modules/__shared__/ActionsOverlay/types.ts (2)

16-19: LGTM! Good mobile interaction support

The LongPressHandler type properly handles mobile interactions, aligning with the requirement to support mobile behavior.


33-36: LGTM! Clean container props interface

The interface is appropriately focused on positioning concerns.

packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx (3)

32-32: LGTM!

The addition of closeOnClick property is consistent with the overlay behavior requirements.


40-40: LGTM!

The addition of closeOnClick property and simplified click handler improve code clarity.


3-3: Verify the component's usage context

The hook returns comment-specific actions (share, pin, edit) rather than the chat room actions (archive, mark as unread, delete) specified in the PR objectives. Please clarify if this component is being repurposed for chat rooms or if this is the correct implementation.

Also applies to: 7-7

packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx (2)

Line range hint 1-31: LGTM! Hook and imports are properly implemented.

The addition of useRef and necessary imports for the overlay functionality is well-structured.


Line range hint 1-132: Verify mobile responsiveness implementation

The PR objectives specify that the component must be consistent across all devices and reuse a component that supports mobile behavior. However, there's no explicit mobile-specific handling visible in the code.

✅ Verification successful

Mobile responsiveness is properly implemented

The component is built with proper mobile responsiveness through multiple layers:

  1. The ChatRoomItem itself has mobile-specific styling:
[theme.breakpoints.down('sm')]: {
  maxWidth: '600px',
  padding: theme.spacing(1.5),
}
  1. The ActionsOverlay component (which wraps ChatRoomItem) has built-in mobile support:
  • Uses SwipeableDrawer for mobile interaction
  • Handles mobile-specific long-press events
  • Uses responsive MUI components (Box, Grid) with proper styling
  1. The component inherits from the design system's breakpoint configurations, as evidenced by the tailwind config using standardized breakpoints.

The implementation satisfies both requirements:

  • Reuses components that support mobile behavior (ActionsOverlay with SwipeableDrawer)
  • Maintains consistency across devices through responsive design patterns
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for mobile-specific implementations or responsive design patterns
rg -l 'useMediaQuery|@media|theme.breakpoints' packages/components/modules/__shared__/ActionsOverlay/

Length of output: 103


Script:

#!/bin/bash
# Let's check the styled components and mobile-related implementations in both ChatRoomItem and ActionsOverlay
rg -A 5 '(styled|@media|breakpoints|useMediaQuery|mobile)' packages/components/modules/messages/ChatRoomsList/ChatRoomItem/styled.ts

# Also check ActionsOverlay's implementation
rg -A 5 '(styled|@media|breakpoints|useMediaQuery|mobile)' packages/components/modules/__shared__/ActionsOverlay/styled.ts

# Check if there are any mobile-specific props or interfaces
ast-grep --pattern 'interface $_ {
  $$$
  mobile?: $_
  $$$
}'

Length of output: 543


Script:

#!/bin/bash
# Let's try to find the styled files with a more flexible search
fd -e ts -e tsx styled

# Search for any mobile-related implementations in the entire components directory
rg -A 5 '(useMediaQuery|@media|breakpoints|mobile)' packages/components/

# Check if ActionsOverlay has any responsive design implementations
rg -A 5 'Box|Grid|Container' packages/components/modules/__shared__/ActionsOverlay/

Length of output: 29762

packages/components/modules/comments/CommentItem/index.tsx (3)

12-12: LGTM! Import changes align with component reuse strategy.

The introduction of ActionsOverlay and removal of CommentOptions aligns with the PR objectives of reusing existing components.


128-165: LGTM! Overlay implementation meets requirements.

The ActionsOverlay implementation successfully integrates the required functionality while maintaining a clean component structure.


128-133: Verify hover behavior matches requirements.

The implementation looks good, but we should verify that the overlay appears within one second of hovering and disappears immediately when the mouse moves away.

Comment on lines 6 to 25
export const ActionOverlayContainer = styled(Box)<ActionOverlayContainerProps>(
({ theme, offsetTop = 0, offsetRight = 0 }) => ({
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.spacing(1),
display: 'flex',
gap: theme.spacing(1),
padding: theme.spacing(0.75, 1),
position: 'absolute',
right: 12 - offsetRight,
top: -12 - offsetTop,
zIndex: 1,
}),
)
Copy link

@coderabbitai coderabbitai bot Nov 28, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider improvements for responsiveness and accessibility

The ActionOverlayContainer implementation has several areas for improvement:

  1. Replace fixed pixel values with theme spacing for consistency:
-    right: 12 - offsetRight,
-    top: -12 - offsetTop,
+    right: theme.spacing(1.5) - offsetRight,
+    top: -theme.spacing(1.5) - offsetTop,
  1. Consider adding hover transition for smooth appearance as per requirements:
    position: 'absolute',
    right: theme.spacing(1.5) - offsetRight,
    top: -theme.spacing(1.5) - offsetTop,
    zIndex: 1,
+    transition: theme.transitions.create(['opacity', 'visibility'], {
+      duration: theme.transitions.duration.shorter,
+    }),
  1. The z-index value of 1 might be too low. Consider using theme.zIndex for consistent layering:
-    zIndex: 1,
+    zIndex: theme.zIndex.tooltip,
  1. Add ARIA attributes for accessibility:
    position: 'absolute',
+    role: 'menu',
+    'aria-label': 'Action options',
📝 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
export const ActionOverlayContainer = styled(Box)<ActionOverlayContainerProps>(
({ theme, offsetTop = 0, offsetRight = 0 }) => ({
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.spacing(1),
display: 'flex',
gap: theme.spacing(1),
padding: theme.spacing(0.75, 1),
position: 'absolute',
right: 12 - offsetRight,
top: -12 - offsetTop,
zIndex: 1,
}),
)
export const ActionOverlayContainer = styled(Box)<ActionOverlayContainerProps>(
({ theme, offsetTop = 0, offsetRight = 0 }) => ({
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.spacing(1),
display: 'flex',
gap: theme.spacing(1),
padding: theme.spacing(0.75, 1),
position: 'absolute',
right: theme.spacing(1.5) - offsetRight,
top: -theme.spacing(1.5) - offsetTop,
role: 'menu',
'aria-label': 'Action options',
transition: theme.transitions.create(['opacity', 'visibility'], {
duration: theme.transitions.duration.shorter,
}),
zIndex: theme.zIndex.tooltip,
}),
)

Copy link
Collaborator

Choose a reason for hiding this comment

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

@pedrotpo I think that's worth doing as well

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 21 to 30
export interface ActionOverlayProps extends BoxProps {
ContainerProps?: BoxProps
enableDelete?: boolean
isDeletingItem?: boolean
handleDeleteItem?: () => void
actions: OverlayAction[]
SwipeableDrawer?: FC<SwipeableDrawerProps>
SwipeableDrawerProps?: Partial<SwipeableDrawerProps>
offsetTop?: number
offsetRight?: number
}
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 missing properties to meet overlay requirements

The interface needs additional properties to fully meet the requirements:

  1. Animation timing control (should appear within 1 second)
  2. Mouse leave handling (should disappear immediately)
  3. Z-index control for proper overlay positioning
 export interface ActionOverlayProps extends BoxProps {
   ContainerProps?: BoxProps
   enableDelete?: boolean
   isDeletingItem?: boolean
   handleDeleteItem?: () => void
-  actions: OverlayAction[]
+  actions: NonEmptyArray<OverlayAction> // ensure array is not empty
   SwipeableDrawer?: FC<SwipeableDrawerProps>
   SwipeableDrawerProps?: Partial<SwipeableDrawerProps>
   offsetTop?: number
   offsetRight?: number
+  zIndex?: number
+  appearanceDelay?: number // in milliseconds, default should be < 1000
+  onMouseLeave?: () => void
 }

Also, consider adding a type guard:

type NonEmptyArray<T> = [T, ...T[]];

Comment on lines 7 to 14
export type OverlayAction = {
label: string
icon: JSX.Element
onClick: () => void
disabled: boolean
hasPermission?: boolean | null
closeOnClick?: boolean
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance type definition for better accessibility and testing

Consider the following improvements to the OverlayAction type:

  1. Make disabled optional with a default value
  2. Add accessibility properties
  3. Add testing identifier
 export type OverlayAction = {
   label: string
   icon: JSX.Element
   onClick: () => void
-  disabled: boolean
+  disabled?: boolean
   hasPermission?: boolean | null
   closeOnClick?: boolean
+  ariaLabel?: string
+  dataTestId?: string
 }
📝 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
export type OverlayAction = {
label: string
icon: JSX.Element
onClick: () => void
disabled: boolean
hasPermission?: boolean | null
closeOnClick?: boolean
}
export type OverlayAction = {
label: string
icon: JSX.Element
onClick: () => void
disabled?: boolean
hasPermission?: boolean | null
closeOnClick?: boolean
ariaLabel?: string
dataTestId?: string
}

Comment on lines 1 to 35
import { FC } from 'react'

import type { SwipeableDrawerProps } from '@baseapp-frontend/design-system'

import { BoxProps } from '@mui/material'

export type OverlayAction = {
label: string
icon: JSX.Element
onClick: () => void
disabled: boolean
hasPermission?: boolean | null
closeOnClick?: boolean
}

export type LongPressHandler = {
isLongPressingItem: boolean
shouldOpenItemOptions: boolean
}

export interface ActionOverlayProps extends BoxProps {
ContainerProps?: BoxProps
enableDelete?: boolean
isDeletingItem?: boolean
handleDeleteItem?: () => void
actions: OverlayAction[]
SwipeableDrawer?: FC<SwipeableDrawerProps>
SwipeableDrawerProps?: Partial<SwipeableDrawerProps>
offsetTop?: number
offsetRight?: number
}

export interface ActionOverlayContainerProps extends BoxProps {
offsetTop?: number
offsetRight?: number
}
Copy link

@coderabbitai coderabbitai bot Nov 28, 2024

Choose a reason for hiding this comment

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

💡 Codebase verification

Missing Storybook documentation for ActionsOverlay component

The component lacks Storybook documentation as evidenced by:

  • No .stories.tsx or .stories.ts files found in the components directory
  • No MDX documentation files referencing the component
  • No documentation files present in the component's directory

Please add Storybook documentation for the ActionsOverlay component to meet the PR requirements. The documentation should showcase:

  • Basic usage
  • Different action configurations
  • Various prop combinations
  • Edge cases (e.g., disabled states, permission states)
🔗 Analysis chain

Verify Storybook documentation existence

The PR requirements mention that the component must be documented in Storybook. Let's verify this requirement is met.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for Storybook documentation file
fd -e stories.tsx -e stories.ts "ActionsOverlay"

Length of output: 48


Script:

#!/bin/bash
# Let's try a broader search for any stories files in the components directory
fd -e stories.tsx -e stories.ts . packages/components/

# Also check if the component is referenced in any MDX files (another common Storybook format)
fd -e mdx . packages/components/ --exec grep -l "ActionsOverlay"

# Finally, let's check the component directory for any documentation
ls -la packages/components/modules/__shared__/ActionsOverlay/

Length of output: 474

Copy link
Collaborator

@anicioalexandre anicioalexandre Nov 29, 2024

Choose a reason for hiding this comment

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

@pt-tsl it would be cool if we could do the storybook for this one, especially now that it is a reusable component

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 57 to 80
<ActionsOverlay
title="Chat"
offsetTop={-12}
actions={[
{
disabled: true,
icon: <LinkIcon />,
label: 'Share Comment',
onClick: () => console.log('Share'),
hasPermission: true,
},
{
disabled: false,
icon: <PenEditIcon />,
label: 'Edit Comment',
onClick: () => console.log('Edit'),
hasPermission: true,
},
]}
enableDelete
handleDeleteItem={() => console.log('Delete')}
isDeletingItem={false}
ref={chatCardRef}
>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Implementation doesn't match requirements

The current implementation has several discrepancies with the PR objectives:

  1. The actions implemented (share/edit) don't match the required actions (archive/mark as unread/delete)
  2. Console.log statements in onClick handlers suggest incomplete implementation
  3. No clear indication of hover behavior implementation

Consider this implementation instead:

 <ActionsOverlay
   title="Chat"
   offsetTop={-12}
   actions={[
     {
-      disabled: true,
-      icon: <LinkIcon />,
-      label: 'Share Comment',
-      onClick: () => console.log('Share'),
+      disabled: false,
+      icon: <ArchiveIcon />,
+      label: 'Archive Chat',
+      onClick: onArchive,
       hasPermission: true,
     },
     {
       disabled: false,
-      icon: <PenEditIcon />,
-      label: 'Edit Comment',
-      onClick: () => console.log('Edit'),
+      icon: <UnreadIcon />,
+      label: 'Mark as Unread',
+      onClick: onMarkUnread,
       hasPermission: true,
     },
   ]}
   enableDelete
-  handleDeleteItem={() => console.log('Delete')}
+  handleDeleteItem={onDelete}
   isDeletingItem={false}
   ref={chatCardRef}
 >

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

})

const longPressHandlers = useLongPress<HTMLDivElement>(
(e: any) => {
Copy link

@coderabbitai coderabbitai bot Nov 28, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using the 'any' type for event parameters

At line 42, the event parameter e is typed as any. Using any reduces type safety and may mask potential issues. Specify a more precise event type to enhance type checking and maintainability.

Apply this diff to specify the correct event type:

- (e: any) => {
+ (e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>) => {
📝 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
(e: any) => {
(e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>) => {

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

setIsDeleteDialogOpen(true)
}

const deviceHasHover = window.matchMedia('(hover: hover)').matches
Copy link

@coderabbitai coderabbitai bot Nov 28, 2024

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure safe usage of 'window' for server-side rendering compatibility

At line 70, using window.matchMedia without checking if window is defined may cause errors during server-side rendering (SSR), where window is undefined. To prevent this issue, add a check to ensure window exists before using it.

Apply this diff to fix the issue:

- const deviceHasHover = window.matchMedia('(hover: hover)').matches
+ const deviceHasHover = typeof window !== 'undefined' && window.matchMedia('(hover: hover)').matches
📝 Committable suggestion

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

Suggested change
const deviceHasHover = window.matchMedia('(hover: hover)').matches
const deviceHasHover = typeof window !== 'undefined' && window.matchMedia('(hover: hover)').matches

Copy link
Collaborator

Choose a reason for hiding this comment

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

@pedrotpo that's a good suggestion

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@pt-tsl pt-tsl force-pushed the BA-1831-action-overlay branch from 158e6e2 to 33e55c5 Compare November 28, 2024 22:56
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

🧹 Outside diff range and nitpick comments (6)
packages/components/modules/comments/CommentItem/index.tsx (3)

49-49: Consider aligning state variable name with query parameter.

The state variable isReplyExpanded is used with a query parameter named isRepliesExpanded. This inconsistency could lead to confusion. Consider using consistent naming.

-  const [isReplyExpanded, setIsReplyExpanded] = useState(false)
+  const [isRepliesExpanded, setIsRepliesExpanded] = useState(false)

Line range hint 63-74: Enhance error handling with user feedback.

While error logging is present, users won't be notified when reply expansion fails. Consider adding user-facing error notifications.

   onComplete: (error) => {
     if (error) {
       console.error(error)
+      // Add user notification here
+      // Example: showErrorNotification('Failed to load replies')
     } else {
       setIsReplyExpanded(true)
     }
   },

128-165: Add accessibility attributes to the overlay.

The overlay should include proper ARIA attributes for better accessibility.

   <ActionsOverlay
     actions={defaultCommentOptions}
     enableDelete={enableDelete && !!comment?.canDelete}
     handleDeleteItem={handleDeleteComment}
     isDeletingItem={isDeletingComment}
     title="Comment"
+    aria-label="Comment actions"
+    role="menu"
     ref={commentItemRef}
   >
packages/components/modules/__shared__/ActionsOverlay/index.tsx (3)

48-50: Typographical corrections in comments

The comments in lines 48-50 contain typographical errors:

  • "comment options's drawer" should be "comment options drawer" or "comment options' drawer".
  • "mobile google chrome devices" should be "mobile Google Chrome devices".

51-53: Simplify className type checking

In lines 51-53, the type checking for className can be simplified. Since className is expected to be a string, and HTMLElement.className returns a string, the additional type check may be unnecessary.

Apply this diff to simplify the code:

- const className = (e?.target as HTMLElement)?.className || ''
- const classNameString = typeof className === 'string' ? className : ''
- const isClickOnBackdrop = classNameString.includes('MuiBackdrop')
+ const className = (e?.target as HTMLElement)?.className || ''
+ const isClickOnBackdrop = className.includes('MuiBackdrop')

210-212: Ensure prop spread order to prevent unintended overrides

In lines 210-212, props from longPressHandlers() and ContainerProps are spread into the Box component. Be cautious of the spread order to ensure that props are not unintentionally overridden.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 158e6e27e0f401791950bc2e0eae5335879e1c61 and 33e55c579361601f7688f335e8cd0854b2dc0c21.

📒 Files selected for processing (11)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/index.tsx (1 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/index.tsx (0 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx (0 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/types.ts (0 hunks)
  • packages/components/modules/comments/CommentItem/index.tsx (4 hunks)
  • packages/components/modules/comments/CommentItem/types.ts (0 hunks)
  • packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx (2 hunks)
  • packages/components/modules/comments/CommentItem/useCommentOptions/types.ts (0 hunks)
  • packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx (3 hunks)
  • packages/components/package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • packages/components/modules/comments/CommentItem/CommentOptions/index.tsx
  • packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx
  • packages/components/modules/comments/CommentItem/CommentOptions/types.ts
  • packages/components/modules/comments/CommentItem/types.ts
  • packages/components/modules/comments/CommentItem/useCommentOptions/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/components/CHANGELOG.md
  • packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx
  • packages/components/package.json
🔇 Additional comments (9)
packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx (4)

31-32: LGTM!

The ref implementation is correct and necessary for the ActionsOverlay component.


57-80: Implementation doesn't match requirements

The current implementation still has discrepancies with the PR objectives:

  1. Actions don't match requirements (share/edit vs archive/mark as unread/delete)
  2. Console.log statements need to be replaced with proper stubs
  3. Hover behavior isn't implemented

Additionally, consider adding hover behavior props:

 <ActionsOverlay
   title="Chat"
   offsetTop={-12}
+  showOnHover={true}
+  hoverDelay={1000}
   actions={[...]}
 >

81-132: LGTM!

The UI structure maintains all necessary elements while properly integrating the overlay component. The layout is well-organized and preserves the existing functionality.


9-9: Verify mobile behavior support

Please confirm that the imported ActionsOverlay from __shared__ is the same component mentioned in the requirements that supports mobile behavior.

✅ Verification successful

Verified: ActionsOverlay component has proper mobile support

The imported ActionsOverlay component from __shared__ is indeed the correct component with mobile behavior support, as evidenced by:

  • It uses device detection to provide different UX for mobile vs desktop: deviceHasHover = window.matchMedia('(hover: hover').matches
  • For mobile devices (non-hover), it implements a long-press interaction with SwipeableDrawer component
  • For desktop (hover devices), it shows a hover-based overlay with action buttons
  • Mobile-specific features include:
    • Long press gesture detection with 400ms threshold
    • Touch-friendly bottom drawer interface
    • Mobile-optimized layout with larger touch targets and clear labels
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if ActionsOverlay is the reused component with mobile support

# Look for mobile-related props or implementations in ActionsOverlay
ast-grep --pattern 'const ActionsOverlay = $$$' '../../../__shared__/ActionsOverlay/index.tsx'

# Check for mobile-related styles
rg -A 5 'mobile|touch|responsive' '../../../__shared__/ActionsOverlay/styled.tsx'

Length of output: 354


Script:

#!/bin/bash
# Let's try searching from the repository root with fd and rg

# Find ActionsOverlay files
fd -t f "ActionsOverlay" 

# Look for mobile-related implementations in ActionsOverlay files
rg -A 5 'mobile|touch|responsive' $(fd -t f "ActionsOverlay")

# Look for ActionsOverlay component definition
ast-grep --pattern 'const ActionsOverlay = $$$'

Length of output: 49162

packages/components/modules/comments/CommentItem/index.tsx (2)

12-12: LGTM! Import changes align with the new overlay functionality.

Also applies to: 16-16


60-61: ⚠️ Potential issue

Add error handling for delete mutation.

The delete operation should handle potential errors to provide feedback to users and maintain a consistent state.

-  const [deleteComment, isDeletingComment] = useCommentDeleteMutation()
+  const [deleteComment, isDeletingComment] = useCommentDeleteMutation({
+    onError: (error) => {
+      console.error('Failed to delete comment:', error);
+      // Add user notification here
+    }
+  })
packages/components/modules/__shared__/ActionsOverlay/index.tsx (3)

42-42: Avoid using the any type for event parameters

At line 42, the event parameter e is typed as any. Using any reduces type safety and may mask potential issues. Specify a more precise event type to enhance type checking and maintainability.


70-70: Ensure safe usage of window for server-side rendering compatibility

At line 70, using window.matchMedia without checking if window is defined may cause errors during server-side rendering (SSR), where window is undefined. To prevent this issue, add a check to ensure window exists before using it.


205-219: Overall implementation looks good

The ActionsOverlay component is well-structured and effectively handles both hover and long-press interactions to display action overlays. The logic is clear, and the use of hooks and props promotes reusability and maintainability.

@@ -1,11 +1,12 @@
import { FC, SyntheticEvent } from 'react'
import { FC, SyntheticEvent, useRef } from 'react'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update imports to match required actions

The current imports (LinkIcon, PenEditIcon) don't align with the required actions (archive, mark as unread, delete). Consider importing the appropriate icons instead.

-import { AvatarWithPlaceholder, LinkIcon, PenEditIcon } from '@baseapp-frontend/design-system'
+import { AvatarWithPlaceholder, ArchiveIcon, UnreadIcon } from '@baseapp-frontend/design-system'

Also applies to: 3-3, 9-9

Copy link
Collaborator

@anicioalexandre anicioalexandre left a comment

Choose a reason for hiding this comment

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

that went better than I thought we could do for customizing this! good job :)

aria-label="actions overlay"
{...SwipeableDrawerProps}
>
<div className="grid grid-cols-[1fr] justify-start gap-2">
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's covert that to a Box styled, please

setIsDeleteDialogOpen(true)
}

const deviceHasHover = window.matchMedia('(hover: hover)').matches
Copy link
Collaborator

Choose a reason for hiding this comment

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

@pedrotpo that's a good suggestion

Comment on lines 6 to 25
export const ActionOverlayContainer = styled(Box)<ActionOverlayContainerProps>(
({ theme, offsetTop = 0, offsetRight = 0 }) => ({
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.spacing(1),
display: 'flex',
gap: theme.spacing(1),
padding: theme.spacing(0.75, 1),
position: 'absolute',
right: 12 - offsetRight,
top: -12 - offsetTop,
zIndex: 1,
}),
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

@pedrotpo I think that's worth doing as well

@@ -143,57 +117,54 @@ const CommentItem: FC<CommentItemProps> = ({
return null
}

const { options = defaultCommentOptions, ...restOfCommentOptionsProps } =
CommentOptionsProps ?? {}
Copy link
Collaborator

Choose a reason for hiding this comment

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

it would be nice if we could keep this and add a ActionsOverlayProps instead

@pt-tsl pt-tsl force-pushed the BA-1831-action-overlay branch from 33e55c5 to f2d8eb6 Compare November 29, 2024 15:24
Copy link

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

🧹 Outside diff range and nitpick comments (10)
packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlayOnButton/index.tsx (2)

1-6: Consider importing action icons for the overlay.

Based on the PR objectives, the overlay should demonstrate archive, mark as unread, and delete actions. Consider importing the corresponding icons from your icon library to make the example more representative of the actual usage.

import React, { RefAttributes } from 'react'
import { Button } from '@mui/material'
+import { ArchiveIcon, UnreadIcon, DeleteIcon } from '@your-icon-library'
import ActionsOverlay from '../..'
import { ActionOverlayProps } from '../../types'

8-10: Add JSDoc documentation for the component.

Since this is a Storybook example component, adding documentation will help other developers understand its purpose and usage better.

+/**
+ * A Storybook example component demonstrating the ActionsOverlay functionality.
+ * Shows how to integrate ActionsOverlay with a button component.
+ * @example
+ * <ActionsOverlayOnButton
+ *   actions={[
+ *     { label: 'Archive', icon: <ArchiveIcon />, onClick: () => {} },
+ *     { label: 'Mark as Unread', icon: <UnreadIcon />, onClick: () => {} },
+ *     { label: 'Delete', icon: <DeleteIcon />, onClick: () => {} }
+ *   ]}
+ * />
+ */
const ActionsOverlayOnButton = (
  props: Omit<ActionOverlayProps, 'ref'> & RefAttributes<HTMLDivElement>,
) => {
packages/design-system/components/icons/ArchiveIcon/index.tsx (2)

6-6: Consider making the icon size configurable

While the current implementation works, consider making the icon size configurable through props to enhance reusability across different contexts. The hardcoded size of 18 might not suit all use cases.

-const ArchiveIcon: FC<SvgIconProps> = ({ sx, ...props }) => (
+const ArchiveIcon: FC<SvgIconProps & { size?: number }> = ({ sx, size = 18, ...props }) => (

Then use the size prop:

-  <SvgIcon sx={{ fontSize: 18, color: 'action.active', ...sx }} {...props}>
+  <SvgIcon sx={{ fontSize: size, color: 'action.active', ...sx }} {...props}>

7-16: Add accessibility attributes to the SVG

To improve accessibility, consider adding ARIA attributes and a title element to the SVG.

-    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
+    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none" 
+        role="img" aria-label="Archive">
+      <title>Archive</title>
       <path
packages/design-system/components/icons/UnreadIcon/index.tsx (2)

5-6: Consider using theme tokens for fontSize.

The implementation looks good, but the hardcoded fontSize of 18 could be moved to the theme system for better maintainability and consistency.

Consider updating the sx prop to use a theme token:

-  <SvgIcon sx={{ fontSize: 18, color: 'action.active', ...sx }} {...props}>
+  <SvgIcon sx={{ fontSize: theme => theme.typography.pxToRem(18), color: 'action.active', ...sx }} {...props}>

7-44: Add accessibility attributes and documentation.

While the SVG implementation is correct, consider the following improvements:

  1. Add ARIA attributes for better accessibility
  2. Add JSDoc comments explaining the visual representation

Consider adding these improvements:

+ /** 
+  * UnreadIcon - Represents a slashed eye icon indicating the unread state
+  * Visual: An eye symbol with a diagonal line through it
+  */
 const UnreadIcon: FC<SvgIconProps> = ({ sx, ...props }) => (
   <SvgIcon sx={{ fontSize: 18, color: 'action.active', ...sx }} {...props}>
-    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none">
+    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"
+         role="img"
+         aria-label="Mark as unread">
packages/components/CHANGELOG.md (1)

7-7: Consider enhancing the changelog entry with more details.

While the current entry captures the core changes, it would be helpful to add:

  • The purpose of the ActionsOverlay (e.g., "to provide hover-activated action buttons")
  • The specific actions it supports (archive, mark as unread, delete)
  • Any notable UI/UX aspects (e.g., "appears on hover within 1s")

Example enhancement:

- Removed CommentOptions from CommentItem component and refactored into ActionsOverlay. Applied ActionsOverlay to CommentItem and ChatRoomItem components.
+ Removed CommentOptions from CommentItem component and refactored into ActionsOverlay - a hover-activated component providing archive, mark as unread, and delete actions. Applied ActionsOverlay to both CommentItem and ChatRoomItem components with a 1-second hover trigger.
packages/design-system/CHANGELOG.md (1)

3-8: Enhance the changelog entry with more context.

While the changelog entry correctly documents the addition of new icons, it could be more descriptive to help other developers understand their purpose and usage.

Consider expanding the entry like this:

 ## 0.0.22

 ### Patch Changes

-Added Archive and Unread icons
+Added Archive and Unread icons for use in chat room action overlays
packages/components/modules/comments/CommentItem/index.tsx (2)

34-34: Add JSDoc comments for the new props.

Consider adding JSDoc comments to document the purpose and usage of ActionOverlayProps and enableDelete props for better maintainability.

+/** Props to customize the actions overlay behavior and appearance */
 ActionOverlayProps,
+/** Whether to enable the delete functionality. Defaults to true */
 enableDelete = true,

132-170: Enhance accessibility attributes.

Consider adding the following accessibility improvements:

  • ARIA labels for interactive elements
  • Role attributes for semantic structure
  • Keyboard navigation support
 <ActionsOverlay
   actions={actions}
   enableDelete={enableDelete && !!comment?.canDelete}
   handleDeleteItem={handleDeleteComment}
   isDeletingItem={isDeletingComment}
   title="Comment"
+  aria-label={`Comment by ${comment.user?.fullName}`}
   {...restOfActionOverlayProps}
   ref={commentItemRef}
 >
-  <CommentContainer>
+  <CommentContainer role="article">
     <AvatarWithPlaceholder
       width={40}
       height={40}
       alt={comment.user?.fullName ?? `Comment's user avatar`}
       src={comment.user?.avatar?.url}
     />
-    <div className="grid gap-3">
+    <div className="grid gap-3" role="region" aria-label="Comment content">
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 33e55c579361601f7688f335e8cd0854b2dc0c21 and f2d8eb6.

📒 Files selected for processing (24)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlay.mdx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlayOnButton/index.tsx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/__storybook__/stories.tsx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/index.tsx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/styled.tsx (1 hunks)
  • packages/components/modules/__shared__/ActionsOverlay/types.ts (1 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/index.tsx (0 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx (0 hunks)
  • packages/components/modules/comments/CommentItem/CommentOptions/types.ts (0 hunks)
  • packages/components/modules/comments/CommentItem/index.tsx (5 hunks)
  • packages/components/modules/comments/CommentItem/types.ts (2 hunks)
  • packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx (2 hunks)
  • packages/components/modules/comments/CommentItem/useCommentOptions/types.ts (0 hunks)
  • packages/components/modules/comments/Comments/__tests__/Comments.cy.tsx (2 hunks)
  • packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx (3 hunks)
  • packages/components/package.json (1 hunks)
  • packages/design-system/CHANGELOG.md (1 hunks)
  • packages/design-system/components/icons/ArchiveIcon/index.tsx (1 hunks)
  • packages/design-system/components/icons/UnreadIcon/index.tsx (1 hunks)
  • packages/design-system/components/icons/index.ts (1 hunks)
  • packages/design-system/package.json (1 hunks)
  • packages/wagtail/CHANGELOG.md (1 hunks)
  • packages/wagtail/package.json (1 hunks)
💤 Files with no reviewable changes (4)
  • packages/components/modules/comments/CommentItem/CommentOptions/index.tsx
  • packages/components/modules/comments/CommentItem/CommentOptions/styled.tsx
  • packages/components/modules/comments/CommentItem/CommentOptions/types.ts
  • packages/components/modules/comments/CommentItem/useCommentOptions/types.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/design-system/package.json
  • packages/wagtail/CHANGELOG.md
  • packages/wagtail/package.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/components/modules/shared/ActionsOverlay/index.tsx
  • packages/components/modules/shared/ActionsOverlay/styled.tsx
  • packages/components/modules/shared/ActionsOverlay/types.ts
  • packages/components/modules/comments/CommentItem/types.ts
  • packages/components/modules/comments/CommentItem/useCommentOptions/index.tsx
  • packages/components/modules/messages/ChatRoomsList/ChatRoomItem/index.tsx
  • packages/components/package.json
🧰 Additional context used
🪛 LanguageTool
packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlay.mdx

[misspelling] ~19-~19: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...a delete action, the component provides a enabler, loading and click handler prop...

(EN_A_VS_AN)

🔇 Additional comments (13)
packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlayOnButton/index.tsx (1)

1-19: Verify mobile behavior compatibility.

The PR objectives mention reusing a component that supports mobile behavior. Please verify that this example demonstrates proper mobile interaction patterns.

✅ Verification successful

Let me gather more information about the implementation details to verify if the mobile behavior is properly handled.


Let me check one more aspect to verify the long press implementation.


Based on the gathered information, I can now provide the final response:

Mobile behavior is properly implemented in the base component

The example correctly demonstrates mobile interaction patterns as it uses the base ActionsOverlay component which includes:

  • Mobile detection via matchMedia('(hover: hover')
  • SwipeableDrawer implementation for mobile view
  • Long press handling with proper mobile-specific fixes (e.g., Chrome touch event propagation)
  • Documented mobile behavior in the component's MDX file

The story serves its purpose by inheriting all mobile functionality from the base component without requiring additional mobile-specific code.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for mobile-related props or documentation in the ActionsOverlay component
rg -A 5 'mobile|touch|responsive' packages/components/modules/__shared__/ActionsOverlay/

Length of output: 2223


Script:

#!/bin/bash
# Check for long press and drawer related implementations
ast-grep --pattern 'const $_ = useLongPress' packages/components/modules/__shared__/ActionsOverlay/index.tsx

# Check for drawer component usage
rg -A 5 'Drawer|SwipeableDrawer' packages/components/modules/__shared__/ActionsOverlay/

# Check for any mobile detection logic
rg 'isMobile|useMediaQuery|matchMedia' packages/components/modules/__shared__/ActionsOverlay/

Length of output: 5999


Script:

#!/bin/bash
# Check for long press hook implementation and mobile-specific logic
ast-grep --pattern 'const $_ = {
  $$$
  isLongPressingItem: $_,
  $$$
}' packages/components/modules/__shared__/ActionsOverlay/index.tsx

# Check for any touch event handlers
rg 'onTouchStart|onTouchEnd|onTouchMove' packages/components/modules/__shared__/ActionsOverlay/

Length of output: 237

packages/components/modules/__shared__/ActionsOverlay/__storybook__/stories.tsx (1)

8-11: Verify the correct component for the story

There's an inconsistency in the metadata:

  • The Meta type refers to ActionsOverlay
  • The component property points to ActionsOverlayOnButton

This might lead to confusion. Please clarify if this is intentional or needs to be corrected.

✅ Verification successful

The component usage in the story is correct

The implementation shows that ActionsOverlayOnButton is a valid wrapper component that demonstrates ActionsOverlay usage with a button. This is a common pattern in Storybook where a wrapper component is used to showcase the main component in a practical context:

  • ActionsOverlayOnButton properly implements and forwards all props to ActionsOverlay
  • The story metadata correctly uses ActionsOverlay type for props while using the demo wrapper as the displayed component
  • This setup allows developers to see how ActionsOverlay works in a real-world scenario with a button
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if ActionsOverlayOnButton is a wrapper or test utility
cat packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlayOnButton.tsx

Length of output: 227


Script:

#!/bin/bash
# Let's first check what files exist in the storybook directory
ls -la packages/components/modules/__shared__/ActionsOverlay/__storybook__/

# Also search for ActionsOverlayOnButton definition in the codebase
rg "ActionsOverlayOnButton" -l

Length of output: 601


Script:

#!/bin/bash
# Let's check the content of both files to understand the relationship
cat packages/components/modules/__shared__/ActionsOverlay/__storybook__/ActionsOverlayOnButton/index.tsx
cat packages/components/modules/__shared__/ActionsOverlay/__storybook__/stories.tsx

Length of output: 1603

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

16-18: Verify the reinstated icon components.

The reinstated icons (PenEditIcon, PinIcon, SendMessageIcon, TrashCanIcon) complement the overlay functionality.

Let's verify the usage of these icons in the ActionsOverlay component:

Also applies to: 20-20

✅ Verification successful

Icons are correctly reinstated and actively used in the codebase

The icons are verified to be properly integrated and used across multiple components:

  • PenEditIcon: Used in comment editing functionality (CommentItem/useCommentOptions)
  • PinIcon: Used in comment pinning features (CommentItem/useCommentOptions, CommentPinnedBadge)
  • SendMessageIcon: Used in SocialInput/SubmitActions and navigation components
  • TrashCanIcon: Used in ActionsOverlay component for deletion actions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of reinstated icons in ActionsOverlay

# Search for imports and usage in ActionsOverlay
echo "Checking icon usage in ActionsOverlay..."
rg -A 5 "PenEditIcon|PinIcon|SendMessageIcon|TrashCanIcon" --type ts --type tsx

Length of output: 200


Script:

#!/bin/bash
# Let's try a different approach to search for these icons

# First, let's find all TypeScript and JavaScript files that might contain these icons
echo "Searching for icon usage in all TypeScript and JavaScript files..."
rg -l "PenEditIcon|PinIcon|SendMessageIcon|TrashCanIcon" --type ts --type js

# Let's also check if there are any React/TSX files specifically
echo -e "\nChecking for TSX/JSX files containing these icons..."
fd -e tsx -e jsx . | xargs rg "PenEditIcon|PinIcon|SendMessageIcon|TrashCanIcon"

# Let's also verify if these icon files actually exist
echo -e "\nVerifying icon files existence..."
fd -e ts -e tsx "PenEditIcon|PinIcon|SendMessageIcon|TrashCanIcon"

Length of output: 4253

packages/design-system/components/icons/ArchiveIcon/index.tsx (2)

1-5: LGTM! Clean imports and proper TypeScript typing

The component is well-structured with appropriate type definitions using React.FC and Material-UI's SvgIconProps.


1-20: Verify Storybook documentation

The PR objectives require documentation in Storybook for new components. Let's verify this requirement is met.

✅ Verification successful

Icon is properly documented in Storybook

The ArchiveIcon is correctly integrated into the design system's documentation:

  • It's exported in the main icons index file
  • It follows the documented icon creation guidelines from the README
  • It's automatically included in the Storybook's Iconography page through the dynamic IconGallery component that renders all exported icons
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for Storybook stories for ArchiveIcon
fd -e stories.tsx -e stories.ts -e stories.jsx -e stories.js . | grep -i "ArchiveIcon"

# Check if the component is exported in any index files for Storybook
rg -l "export.*ArchiveIcon" "packages/design-system/**/*.stories.*"

Length of output: 234


Script:

#!/bin/bash
# Let's first check if there are any story files in the design system
fd -e stories.tsx -e stories.ts -e stories.jsx -e stories.js . packages/design-system/

# Let's also check the component's directory structure
ls -la packages/design-system/components/icons/ArchiveIcon/

# Check if there are any story files for icons in general
fd -e stories.tsx -e stories.ts -e stories.jsx -e stories.js . packages/design-system/components/icons/

Length of output: 429


Script:

#!/bin/bash
# Let's check if there's a common story file for all icons
fd "icons?.stories" packages/design-system/

# Check the structure of other icon components to understand the pattern
ls -R packages/design-system/components/icons/

# Look for any documentation patterns in the design system
fd "README|DOCUMENTATION" packages/design-system/

Length of output: 2154


Script:

#!/bin/bash
# Let's check the content of the icons documentation
cat packages/design-system/components/icons/__storybook__/Iconography.mdx
cat packages/design-system/components/icons/README.md

# Check if ArchiveIcon is exported in the icons index
cat packages/design-system/components/icons/index.ts

Length of output: 4381

packages/design-system/components/icons/UnreadIcon/index.tsx (3)

1-3: LGTM! Clean and minimal imports.

The imports are well-organized and include only the necessary types and components.


48-48: LGTM! Clean export statement.

The default export is appropriate for this component.


1-48: Verify Storybook documentation requirement.

The PR objectives mention that new components must be documented in Storybook. Please ensure that a story is created for this component.

✅ Verification successful

Storybook documentation is already implemented correctly

The UnreadIcon is automatically included in the Iconography documentation through the central Iconography.mdx file, which dynamically imports and displays all icons from the icons directory. This is the standard documentation approach for icons in this design system, as evidenced by the __storybook__/Iconography.mdx file that creates a gallery of all available icons.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if Storybook documentation exists for UnreadIcon
fd -e stories.tsx -e stories.mdx "UnreadIcon" packages/design-system/

Length of output: 69


Script:

#!/bin/bash
# Let's check if there are any story files in the icons directory and its structure
fd . "packages/design-system/components/icons" -t f

# Also check if other icons have stories for consistency
fd -e stories.tsx -e stories.mdx . "packages/design-system/components/icons"

Length of output: 1829


Script:

#!/bin/bash
# Let's check the content of the Iconography.mdx to understand the documentation approach
cat packages/design-system/components/icons/__storybook__/Iconography.mdx

# Also check if icons are documented in any parent storybook files
fd -e stories.tsx -e stories.mdx . packages/design-system/components --max-depth 1

Length of output: 606

packages/components/CHANGELOG.md (1)

3-4: LGTM! Version and categorization are appropriate.

The patch version increment (0.0.21) is appropriate since these changes add functionality without breaking existing features.

packages/design-system/CHANGELOG.md (1)

3-4: LGTM: Version increment follows semantic versioning.

The patch version increment is appropriate for adding new icons, as this is a non-breaking change.

packages/components/modules/comments/CommentItem/index.tsx (2)

12-12: LGTM: Import changes align with the new architecture.

The addition of ActionsOverlay and useCommentDeleteMutation imports correctly supports the migration from CommentOptions to the new overlay system.

Also applies to: 16-16


124-127: Enhance delete handler with optimistic updates and loading state.

The current implementation could benefit from optimistic updates and better loading state handling for improved user experience.

packages/components/modules/comments/Comments/__tests__/Comments.cy.tsx (1)

149-149: LGTM! Verify similar test files for consistency.

The button name changes from "delete comment" to "delete item" align with the standardization of action buttons across comments and chat rooms.

Let's verify if similar changes are needed in other test files:

Also applies to: 160-160

✅ Verification successful

Changes are isolated to this test file

The search results confirm that the button name change from "delete comment" to "delete item" is isolated to packages/components/modules/comments/Comments/__tests__/Comments.cy.tsx. No other test files in the codebase use the "delete comment" pattern, and the new "delete item" pattern is only found in this file. This is consistent with the changes being part of the standardization effort in this specific component.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for other test files that might need similar button name updates
# Look for test files containing "delete comment" button references

# Search in test files
rg -t tsx -t ts "delete comment" "**/__tests__/**"

# Search specifically in Cypress test files
rg -g "*.cy.{tsx,ts}" "delete comment"

Length of output: 121


Script:

#!/bin/bash
# Let's try a different approach using fd to find test files and then search within them
# First, find all Cypress test files
fd -e cy.tsx -e cy.ts | xargs rg -l "delete.*comment"

# Also search in regular test files
fd -e test.tsx -e test.ts | xargs rg -l "delete.*comment"

# Let's also search for the new pattern to understand the scope
fd -e cy.tsx -e cy.ts | xargs rg -l "delete.*item"

Length of output: 240

Comment on lines +17 to +38
export const DefaultActionsOverlay: Story = {
name: 'ActionsOverlay',
args: {
title: 'Button',
enableDelete: true,
handleDeleteItem: () => {},
offsetRight: 0,
offsetTop: 0,
ContainerProps: {
sx: { width: '100px' },
},
actions: [
{
label: 'Archive',
icon: <ArchiveIcon />,
onClick: () => {},
hasPermission: true,
closeOnClick: true,
},
],
},
}
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 stories demonstrating responsive behavior

The PR objectives specify that the overlay must behave consistently across all devices and screen sizes. Consider adding additional stories that demonstrate:

  • Different screen sizes
  • Various overlay positions
  • Mobile behavior

Add stories like:

export const MobileOverlay: Story = {
  name: 'Mobile View',
  parameters: {
    viewport: { defaultViewport: 'mobile1' },
  },
  args: {
    // ... mobile specific args
  },
}

export const TabletOverlay: Story = {
  name: 'Tablet View',
  parameters: {
    viewport: { defaultViewport: 'tablet' },
  },
  args: {
    // ... tablet specific args
  },
}

🛠️ Refactor suggestion

Add interaction tests for hover behavior

The PR objectives specify specific timing requirements for the overlay:

  • Should appear within 1 second of hover
  • Should disappear immediately when mouse leaves

Consider adding interaction tests to verify this behavior.

Add an interaction test:

export const HoverBehavior: Story = {
  name: 'Hover Behavior',
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    
    // Test hover appearance
    await userEvent.hover(button);
    // Verify overlay appears within 1 second
    await waitFor(() => {
      expect(canvas.getByRole('menu')).toBeVisible();
    }, { timeout: 1000 });
    
    // Test hover disappearance
    await userEvent.unhover(button);
    // Verify immediate disappearance
    expect(canvas.queryByRole('menu')).not.toBeInTheDocument();
  },
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants