From 0f7bae13e298485e50b470b8d0564b06b5253696 Mon Sep 17 00:00:00 2001 From: Hemachandar <132386067+hmacr@users.noreply.github.com> Date: Wed, 28 Feb 2024 07:34:33 +0530 Subject: [PATCH] feat: Archive all notifications (#6599) * feat: Archive all notifications * use non-modal notification menu * don't show icons in context menu --- app/actions/definitions/notifications.tsx | 17 ++++- app/components/ContextMenu/index.tsx | 10 ++- .../Notifications/Notifications.tsx | 17 ++--- app/menus/NotificationMenu.tsx | 73 +++++++++++++++++++ app/stores/NotificationsStore.ts | 14 ++++ .../api/notifications/notifications.test.ts | 63 ++++++++++++++++ .../routes/api/notifications/notifications.ts | 13 +++- shared/i18n/locales/en_US/translation.json | 1 + 8 files changed, 191 insertions(+), 17 deletions(-) create mode 100644 app/menus/NotificationMenu.tsx diff --git a/app/actions/definitions/notifications.tsx b/app/actions/definitions/notifications.tsx index ec77b7058..fa674d5f5 100644 --- a/app/actions/definitions/notifications.tsx +++ b/app/actions/definitions/notifications.tsx @@ -1,4 +1,4 @@ -import { MarkAsReadIcon } from "outline-icons"; +import { ArchiveIcon, MarkAsReadIcon } from "outline-icons"; import * as React from "react"; import { createAction } from ".."; import { NotificationSection } from "../sections"; @@ -13,4 +13,17 @@ export const markNotificationsAsRead = createAction({ visible: ({ stores }) => stores.notifications.approximateUnreadCount > 0, }); -export const rootNotificationActions = [markNotificationsAsRead]; +export const markNotificationsAsArchived = createAction({ + name: ({ t }) => t("Archive all notifications"), + analyticsName: "Mark notifications as archived", + section: NotificationSection, + icon: , + iconInContextMenu: false, + perform: ({ stores }) => stores.notifications.markAllAsArchived(), + visible: ({ stores }) => stores.notifications.orderedData.length > 0, +}); + +export const rootNotificationActions = [ + markNotificationsAsRead, + markNotificationsAsArchived, +]; diff --git a/app/components/ContextMenu/index.tsx b/app/components/ContextMenu/index.tsx index ae3938d62..277a420c5 100644 --- a/app/components/ContextMenu/index.tsx +++ b/app/components/ContextMenu/index.tsx @@ -38,6 +38,8 @@ export type Placement = type Props = MenuStateReturn & { "aria-label"?: string; + /** Reference to the rendered menu div element */ + menuRef?: React.RefObject; /** The parent menu state if this is a submenu. */ parentMenuState?: Omit; /** Called when the context menu is opened. */ @@ -52,6 +54,7 @@ type Props = MenuStateReturn & { }; const ContextMenu: React.FC = ({ + menuRef, children, onOpen, onClose, @@ -105,7 +108,12 @@ const ContextMenu: React.FC = ({ // trigger and the bottom of the window return ( <> - + {(props) => ( {t("Notifications")} - + {notifications.approximateUnreadCount > 0 && ( )} - - - - + + ( { + const menuRef = React.useRef(null); + const menu = useMenuState(); + const context = useActionContext(); + const items: MenuItem[] = React.useMemo( + () => [ + actionToMenuItem(markNotificationsAsArchived, context), + { + type: "button", + title: "Notification settings", + visible: true, + onClick: () => performAction(navigateToNotificationSettings, context), + }, + ], + [context] + ); + + useOnClickOutside( + menuRef, + (event) => { + if (menu.visible) { + event.stopPropagation(); + event.preventDefault(); + menu.hide(); + } + }, + { capture: true } + ); + + return ( + <> + + {(props) => ( + + )} + + +