Skip to content

Comments

[WEB-2555] fix: add "mark all as read" in the notifications header#5770

Merged
pushya22 merged 2 commits intopreviewfrom
fix/mark-all-as-read
Oct 8, 2024
Merged

[WEB-2555] fix: add "mark all as read" in the notifications header#5770
pushya22 merged 2 commits intopreviewfrom
fix/mark-all-as-read

Conversation

@sharma01ketan
Copy link
Contributor

@sharma01ketan sharma01ketan commented Oct 8, 2024

[WEB-2555]

This PR aims to relocate the "Mark all as read" button from the dropdown to the header in the notifications header.

Previous State:

Screen.Recording.2024-10-08.at.1.06.15.PM.mov

New State:

Note: The below video is recorded on 3G speed using dev-tools

Screen.Recording.2024-10-08.at.1.07.00.PM.mov

Summary by CodeRabbit

  • New Features

    • Users can now mark all notifications as read with a new tooltip and loading indicator.
    • The notification sidebar has been enhanced for better usability while maintaining existing refresh functionality.
  • Bug Fixes

    • Removed unused event tracking functionality, streamlining the notification menu options.
  • Refactor

    • Simplified the props structure for the notification components.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2024

Walkthrough

The changes involve modifications to two components: NotificationHeaderMenuOption and NotificationSidebarHeaderOptions. The workspaceSlug property has been removed from the NotificationHeaderMenuOption type, simplifying the component by eliminating unused functionality, including the useEventTracker hook and the handleMarkAllNotificationsAsRead function. In contrast, the NotificationSidebarHeaderOptions component has been enhanced with a new function to mark all notifications as read, incorporating event tracking and visual feedback during the operation.

Changes

File Path Change Summary
web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx - Removed workspaceSlug from TNotificationHeaderMenuOption type.
- Eliminated useEventTracker and handleMarkAllNotificationsAsRead function.
- Simplified popoverMenuOptions by removing the option to mark all notifications as read.
web/core/components/workspace-notifications/sidebar/header/options/root.tsx - Added imports for CheckCheck, Spinner, and NOTIFICATIONS_READ.
- Integrated useEventTracker and defined handleMarkAllNotificationsAsRead function.
- Updated return statement to include a tooltip for marking notifications as read, with loading state represented by a Spinner.

Possibly related PRs

Suggested labels

🐛bug, 🎨UI / UX

Suggested reviewers

  • SatishGandham
  • sriramveeraghanta

Poem

In the sidebar where notifications dwell,
A rabbit hops and rings a bell.
With options trimmed, the menu's neat,
Mark all as read, a simple feat!
No more clutter, just the best,
Hooray for changes, we’re truly blessed! 🐇✨


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
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (1)
web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx (1)

15-15: LGTM: Type definition updated for flexibility.

The change to make workspaceSlug optional in the TNotificationHeaderMenuOption type is appropriate, given that it's no longer directly used within the component.

Consider adding a brief comment explaining why workspaceSlug is optional, to improve code maintainability. For example:

type TNotificationHeaderMenuOption = {
  // Optional: workspaceSlug is not directly used in this component but may be required by parent components
  workspaceSlug?: string;
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 39eabc2 and d9eb215.

📒 Files selected for processing (2)
  • web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx (2 hunks)
  • web/core/components/workspace-notifications/sidebar/header/options/root.tsx (4 hunks)
🧰 Additional context used
🔇 Additional comments (5)
web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx (4)

5-5: LGTM: Import addition is consistent with component changes.

The addition of the Check icon import aligns with the modifications made to the component's functionality, as mentioned in the AI summary.


Line range hint 1-85: Summary: Changes align with PR objectives and improve component structure.

The modifications to this file successfully simplify the NotificationHeaderMenuOption component by removing unused functionality and props. These changes appear to support the PR objective of relocating the "Mark all as read" button to the notifications header.

Key points:

  1. Removal of unused workspaceSlug prop and related functionality.
  2. Simplification of the component structure.
  3. Removal of event tracking related to marking all notifications as read.

The changes are well-implemented and improve the overall structure of the component. However, ensure that the "Mark all as read" functionality has been properly implemented in the new location as per the PR objectives.


7-7: LGTM: New UI component import added.

The addition of the PopoverMenu import from "@plane/ui" is appropriate for the changes made to the component.

Please ensure that the PopoverMenu component is properly utilized within this file. You can verify this by running the following command:

✅ Verification successful

Action Required: Verify the Usage of PopoverMenu Component

Please run the following command to ensure that the PopoverMenu component is utilized within root.tsx:


Verification Successful: PopoverMenu Component Usage Confirmed

The PopoverMenu component is properly utilized within the NotificationHeaderMenuOption component in root.tsx.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of PopoverMenu component
# Expected: The PopoverMenu component should be used in the NotificationHeaderMenuOption component

rg --type typescript 'PopoverMenu' web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx

Length of output: 157


Script:

#!/bin/bash
# Description: Verify the usage of PopoverMenu component
# Expected: The PopoverMenu component should be used in the NotificationHeaderMenuOption component

rg 'PopoverMenu' web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx

Length of output: 413


28-30: LGTM: Component simplified as per requirements.

The removal of unused props, the useEventTracker hook, and the handleMarkAllNotificationsAsRead function aligns with the goal of simplifying the component.

Please confirm that the functionality for marking all notifications as read has been implemented elsewhere or is no longer required. You can verify this by searching for similar functionality in other components:

✅ Verification successful

Please run the following shell script to search for "mark all as read" functionality without specifying an unrecognized file type:


LGTM: "Mark all as read" functionality remains implemented within the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for "mark all as read" functionality in other components
# Expected: Find implementation of marking all notifications as read in another component

rg --type typescript 'markAllNotificationsAsRead|mark all as read' web/

Length of output: 157


Script:

# 
#!/bin/bash
# Description: Search for "mark all as read" functionality in other components
# Expected: Find implementation of marking all notifications as read in another component

rg 'markAllNotificationsAsRead|mark all as read' web/

Length of output: 1112

web/core/components/workspace-notifications/sidebar/header/options/root.tsx (1)

78-78: Verify all usages of NotificationHeaderMenuOption after prop removal.

The workspaceSlug prop has been removed from NotificationHeaderMenuOption. Ensure that all instances where this component is used have been updated to prevent potential errors.

Run the following script to locate any remaining usages passing the outdated prop:

This will help identify and update any outdated component usages.

import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification";
// hooks
import { useWorkspaceNotifications } from "@/hooks/store";
import { useEventTracker, useWorkspaceNotifications } from "@/hooks/store";
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 8, 2024

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor to prevent multiple calls to useWorkspaceNotifications.

You are invoking useWorkspaceNotifications() twice to destructure different values. This can be optimized by combining them into a single call to enhance performance and readability.

Apply the following change:

 const { isMobile } = usePlatformOS();
-const { loader, getNotifications } = useWorkspaceNotifications();
+const { loader, getNotifications, markAllNotificationsAsRead } = useWorkspaceNotifications();
 const { captureEvent } = useEventTracker();
-const { markAllNotificationsAsRead } = useWorkspaceNotifications();

Also applies to: 23-24

Copy link
Collaborator

Choose a reason for hiding this comment

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

This makes sense, can you fix this

Copy link
Contributor

Choose a reason for hiding this comment

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

@gakshita, sure, I've applied the refactoring to combine the calls to useWorkspaceNotifications() into a single call. Here's the updated code:

import { FC } from "react";
import { observer } from "mobx-react";
import { CheckCheck, RefreshCw } from "lucide-react";
import { Spinner, Tooltip } from "@plane/ui";
// components
import { NotificationFilter, NotificationHeaderMenuOption } from "@/components/workspace-notifications";
// constants
import { NOTIFICATIONS_READ } from "@/constants/event-tracker";
import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification";
// hooks
import { useEventTracker, useWorkspaceNotifications } from "@/hooks/store";
import { usePlatformOS } from "@/hooks/use-platform-os";

type TNotificationSidebarHeaderOptions = {
  workspaceSlug: string;
};

export const NotificationSidebarHeaderOptions: FC<TNotificationSidebarHeaderOptions> = observer((props) => {
  const { workspaceSlug } = props;
  // hooks
  const { isMobile } = usePlatformOS();
  const { loader, getNotifications, markAllNotificationsAsRead } = useWorkspaceNotifications();
  const { captureEvent } = useEventTracker();

  const refreshNotifications = async () => {
    if (loader) return;
    try {
      await getNotifications(
        workspaceSlug,
        ENotificationLoader.MUTATION_LOADER,
        ENotificationQueryParamType.CURRENT
      );
    } catch (error) {
      console.error(error);
    }
  };

  const handleMarkAllNotificationsAsRead = async () => {
    // NOTE: We are using loader to prevent continuous requests when we are marking all notifications as read
    if (loader) return;
    try {
      await markAllNotificationsAsRead(workspaceSlug);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div className="relative flex justify-center items-center gap-2 text-sm">
      {/* mark all notifications as read */}
      <Tooltip tooltipContent="Mark all as read" isMobile={isMobile} position="bottom">
        <div
          className="flex-shrink-0 w-5 h-5 flex justify-center items-center overflow-hidden cursor-pointer transition-all hover:bg-custom-background-80 rounded-sm"
          onClick={() => {
            captureEvent(NOTIFICATIONS_READ);
            handleMarkAllNotificationsAsRead();
          }}
        >
          {loader === ENotificationLoader.MARK_ALL_AS_READY ? (
            <Spinner height="14px" width="14px" />
          ) : (
            <CheckCheck className="h-3 w-3" />
          )}
        </div>
      </Tooltip>

      {/* refetch current notifications */}
      <Tooltip tooltipContent="Refresh" isMobile={isMobile} position="bottom">
        <div
          className="flex-shrink-0 w-5 h-5 flex justify-center items-center overflow-hidden cursor-pointer transition-all hover:bg-custom-background-80 rounded-sm"
          onClick={refreshNotifications}
        >
          <RefreshCw
            className={`h-3 w-3 ${
              loader === ENotificationLoader.MUTATION_LOADER ? "animate-spin" : ""
            }`}
          />
        </div>
      </Tooltip>

      {/* notification filters */}
      <NotificationFilter />

      {/* notification menu options */}
      <NotificationHeaderMenuOption />
    </div>
  );
});

This change enhances performance and readability by reducing unnecessary calls to the hook.

(^‿^)

};

const handleMarkAllNotificationsAsRead = async () => {
// NOTE: We are using loader to prevent continues request when we are making all the notification to read
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the typo and improve the clarity of the comment.

The comment contains grammatical errors that might lead to confusion.

Apply this fix:

-// NOTE: We are using loader to prevent continues request when we are making all the notification to read
+// NOTE: We are using loader to prevent continuous requests when marking all notifications as read
📝 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
// NOTE: We are using loader to prevent continues request when we are making all the notification to read
// NOTE: We are using loader to prevent continuous requests when marking all notifications as read

Comment on lines +39 to +42
await markAllNotificationsAsRead(workspaceSlug);
} catch (error) {
console.error(error);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling by notifying the user upon failure.

In the catch block, errors are logged to the console, but the user remains uninformed. Providing user feedback improves the user experience.

Consider adding a user notification:

 } catch (error) {
   console.error(error);
+  // Optionally, display an error message to the user
+  // showToast("Failed to mark all notifications as read.", "error");
 }

Committable suggestion was skipped due to low confidence.

Comment on lines +37 to +43
if (loader) return;
try {
await markAllNotificationsAsRead(workspaceSlug);
} catch (error) {
console.error(error);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Ensure the loader state correctly prevents concurrent requests.

Currently, you're checking if (loader) return;, which might block the action if any loader is active. To prevent unintended blocking, check for the specific loader state related to marking notifications as read.

Update the condition as follows:

-if (loader) return;
+if (loader === ENotificationLoader.MARK_ALL_AS_READY) return;

This ensures that only the relevant loader state prevents concurrent requests for this action.

Committable suggestion was skipped due to low confidence.


export const NotificationHeaderMenuOption: FC<TNotificationHeaderMenuOption> = observer((props) => {
const { workspaceSlug } = props;
export const NotificationHeaderMenuOption: FC<TNotificationHeaderMenuOption> = observer(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since you removed the props you can remove its type declaration as well

Copy link
Contributor

@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 (1)
web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx (1)

24-26: LGTM: Component simplification.

The removal of unused props, functions, and hooks simplifies the component and aligns with the PR objectives of relocating the "Mark all as read" functionality.

Consider removing the TNotificationHeaderMenuOption type declaration since it's no longer used in the component props.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d9eb215 and c863eb0.

📒 Files selected for processing (2)
  • web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx (2 hunks)
  • web/core/components/workspace-notifications/sidebar/header/options/root.tsx (4 hunks)
🧰 Additional context used
🔇 Additional comments (8)
web/core/components/workspace-notifications/sidebar/header/options/menu-option/root.tsx (4)

5-5: LGTM: Import reordering.

The reordering of imported icons improves code readability and maintains consistency.


7-7: LGTM: Import reordering.

The reordering of imported components improves code readability and maintains consistency.


12-12: LGTM: Import reordering.

The reordering of the useWorkspaceNotifications import improves code readability and maintains consistency.


Line range hint 1-78: Overall assessment: Changes align with PR objectives.

The modifications to the NotificationHeaderMenuOption component successfully simplify its structure by removing unused functionality related to marking all notifications as read. This aligns well with the PR objective of relocating the "Mark all as read" button to the notifications header.

The changes include:

  1. Removal of the workspaceSlug prop and associated functionality.
  2. Elimination of the useEventTracker hook and handleMarkAllNotificationsAsRead function.
  3. Simplification of the component's props and internal logic.

These alterations contribute to a more focused and maintainable component, supporting the overall goal of improving the user interface for notification management.

web/core/components/workspace-notifications/sidebar/header/options/root.tsx (4)

3-4: LGTM: Import changes are appropriate.

The new imports from 'lucide-react' and '@plane/ui' are necessary for the added UI elements. The NOTIFICATIONS_READ constant and useEventTracker hook are correctly imported for the new functionality.

Also applies to: 8-8, 11-11


46-61: LGTM: UI changes for "Mark all as read" functionality.

The new "Mark all as read" button with its tooltip and loading state is well-implemented and aligns with the PR objectives. The use of Spinner and CheckCheck icons provides clear visual feedback to the user.


22-23: 🛠️ Refactor suggestion

Optimize hook usage.

The useWorkspaceNotifications hook is called twice in the component. To improve performance and readability, consider combining these calls.

Apply the following change:

-const { loader, getNotifications } = useWorkspaceNotifications();
+const { loader, getNotifications, markAllNotificationsAsRead } = useWorkspaceNotifications();
 const { captureEvent } = useEventTracker();
-const { markAllNotificationsAsRead } = useWorkspaceNotifications();

Likely invalid or redundant comment.


77-77: Verify the impact of removing workspaceSlug prop.

The workspaceSlug prop has been removed from the NotificationHeaderMenuOption component. Ensure that this change doesn't break any functionality in the NotificationHeaderMenuOption component.

Run the following script to check for any remaining uses of workspaceSlug in the NotificationHeaderMenuOption component:

Comment on lines +34 to +42
const handleMarkAllNotificationsAsRead = async () => {
// NOTE: We are using loader to prevent continues request when we are making all the notification to read
if (loader) return;
try {
await markAllNotificationsAsRead(workspaceSlug);
} catch (error) {
console.error(error);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refine loader state check for better concurrency control.

The current loader check might prevent the action if any loader is active. Consider checking for the specific loader state related to marking notifications as read.

Update the condition as follows:

-if (loader) return;
+if (loader === ENotificationLoader.MARK_ALL_AS_READY) return;

This ensures that only the relevant loader state prevents concurrent requests for this action.

📝 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 handleMarkAllNotificationsAsRead = async () => {
// NOTE: We are using loader to prevent continues request when we are making all the notification to read
if (loader) return;
try {
await markAllNotificationsAsRead(workspaceSlug);
} catch (error) {
console.error(error);
}
};
const handleMarkAllNotificationsAsRead = async () => {
// NOTE: We are using loader to prevent continues request when we are making all the notification to read
if (loader === ENotificationLoader.MARK_ALL_AS_READY) return;
try {
await markAllNotificationsAsRead(workspaceSlug);
} catch (error) {
console.error(error);
}
};

🛠️ Refactor suggestion

Enhance error handling with user feedback.

Currently, errors are only logged to the console. Consider providing feedback to the user when an error occurs.

Add user notification in the catch block:

 } catch (error) {
   console.error(error);
+  // TODO: Implement a user-facing error notification
+  // For example: showToast("Failed to mark all notifications as read. Please try again.", "error");
 }

This improvement will enhance the user experience by keeping them informed of any issues.

Committable suggestion was skipped due to low confidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants