From c9a8e8fc04928bc4154dab03a1fe5a5d8e9f82f2 Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Mon, 9 Dec 2024 17:19:21 +0530 Subject: [PATCH 1/8] chore: adjusted increment/decrement for unread count --- .../store/notifications/workspace-notifications.store.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/core/store/notifications/workspace-notifications.store.ts b/web/core/store/notifications/workspace-notifications.store.ts index b3ba8820353..0f12bfcca0f 100644 --- a/web/core/store/notifications/workspace-notifications.store.ts +++ b/web/core/store/notifications/workspace-notifications.store.ts @@ -50,7 +50,7 @@ export interface IWorkspaceNotificationStore { // actions setCurrentNotificationTab: (tab: TNotificationTab) => void; setCurrentSelectedNotificationId: (notificationId: string | undefined) => void; - setUnreadNotificationsCount: (type: "increment" | "decrement") => void; + setUnreadNotificationsCount: (type: "increment" | "decrement", newCount?: number) => void; getUnreadNotificationsCount: (workspaceSlug: string) => Promise; getNotifications: ( workspaceSlug: string, @@ -285,16 +285,16 @@ export class WorkspaceNotificationStore implements IWorkspaceNotificationStore { * @param { "increment" | "decrement" } type * @returns { void } */ - setUnreadNotificationsCount = (type: "increment" | "decrement"): void => { + setUnreadNotificationsCount = (type: "increment" | "decrement", newCount: number = 1): void => { switch (this.currentNotificationTab) { case ENotificationTab.ALL: update(this.unreadNotificationsCount, "total_unread_notifications_count", (count: 0) => - type === "increment" ? count + 1 : count - 1 + type === "increment" ? count + newCount : count - newCount ); break; case ENotificationTab.MENTIONS: update(this.unreadNotificationsCount, "mention_unread_notifications_count", (count: 0) => - type === "increment" ? count + 1 : count - 1 + type === "increment" ? count + newCount : count - newCount ); break; default: From bf57d9e6d63c321924640dbdd75df0aee23a89ec Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Mon, 9 Dec 2024 17:54:24 +0530 Subject: [PATCH 2/8] chore: improved param handling for unread notification count function --- .../notification-card/options/snooze/modal.tsx | 1 - .../notifications/workspace-notifications.store.ts | 14 ++++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx b/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx index 36302aa5f0c..e7bed668816 100644 --- a/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx +++ b/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx @@ -5,7 +5,6 @@ import { useParams } from "next/navigation"; import { useForm, Controller } from "react-hook-form"; import { X } from "lucide-react"; import { Transition, Dialog } from "@headlessui/react"; -import { TNotification } from "@plane/types"; import { Button, CustomSelect } from "@plane/ui"; // components import { DateDropdown } from "@/components/dropdowns"; diff --git a/web/core/store/notifications/workspace-notifications.store.ts b/web/core/store/notifications/workspace-notifications.store.ts index 0f12bfcca0f..a0de7bc0f60 100644 --- a/web/core/store/notifications/workspace-notifications.store.ts +++ b/web/core/store/notifications/workspace-notifications.store.ts @@ -286,15 +286,21 @@ export class WorkspaceNotificationStore implements IWorkspaceNotificationStore { * @returns { void } */ setUnreadNotificationsCount = (type: "increment" | "decrement", newCount: number = 1): void => { + const validCount = Math.max(0, Math.abs(newCount)); + switch (this.currentNotificationTab) { case ENotificationTab.ALL: - update(this.unreadNotificationsCount, "total_unread_notifications_count", (count: 0) => - type === "increment" ? count + newCount : count - newCount + update( + this.unreadNotificationsCount, + "total_unread_notifications_count", + (count: number) => +Math.max(0, type === "increment" ? count + validCount : count - validCount) ); break; case ENotificationTab.MENTIONS: - update(this.unreadNotificationsCount, "mention_unread_notifications_count", (count: 0) => - type === "increment" ? count + newCount : count - newCount + update( + this.unreadNotificationsCount, + "mention_unread_notifications_count", + (count: number) => +Math.max(0, type === "increment" ? count + validCount : count - validCount) ); break; default: From bc37bf80c70bc21316dc36cc0c10e87a9a0bf349 Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Tue, 10 Dec 2024 19:36:35 +0530 Subject: [PATCH 3/8] chore:file restructuring --- .../(projects)/notifications/layout.tsx | 2 +- .../workspace-notifications/index.ts | 2 +- .../workspace-notifications/root.tsx | 142 ++++++------------ .../workspace-notifications/index.ts | 1 + .../workspace-notifications/root.tsx | 115 ++++++++++++++ .../sidebar/notification-card/index.ts | 1 - .../sidebar/notification-card/root.tsx | 56 ------- 7 files changed, 160 insertions(+), 159 deletions(-) create mode 100644 web/core/components/workspace-notifications/root.tsx delete mode 100644 web/core/components/workspace-notifications/sidebar/notification-card/root.tsx diff --git a/web/app/[workspaceSlug]/(projects)/notifications/layout.tsx b/web/app/[workspaceSlug]/(projects)/notifications/layout.tsx index 7d71948d838..e3d73036361 100644 --- a/web/app/[workspaceSlug]/(projects)/notifications/layout.tsx +++ b/web/app/[workspaceSlug]/(projects)/notifications/layout.tsx @@ -1,7 +1,7 @@ "use client"; // components -import { NotificationsSidebarRoot } from "@/plane-web/components/workspace-notifications"; +import { NotificationsSidebarRoot } from "@/components/workspace-notifications"; export default function ProjectInboxIssuesLayout({ children }: { children: React.ReactNode }) { return ( diff --git a/web/ce/components/workspace-notifications/index.ts b/web/ce/components/workspace-notifications/index.ts index c8711b96a4c..1efe34c51ec 100644 --- a/web/ce/components/workspace-notifications/index.ts +++ b/web/ce/components/workspace-notifications/index.ts @@ -1 +1 @@ -export * from './root' \ No newline at end of file +export * from "./root"; diff --git a/web/ce/components/workspace-notifications/root.tsx b/web/ce/components/workspace-notifications/root.tsx index 35c61263df0..bfff113bafe 100644 --- a/web/ce/components/workspace-notifications/root.tsx +++ b/web/ce/components/workspace-notifications/root.tsx @@ -1,114 +1,56 @@ "use client"; -import { FC, useCallback } from "react"; +import { FC } from "react"; import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; // components -import { Header, Row, ERowVariant, EHeaderVariant, ContentWrapper } from "@plane/ui"; -import { CountChip } from "@/components/common"; -import { - NotificationsLoader, - NotificationEmptyState, - NotificationSidebarHeader, - AppliedFilters, - NotificationCardListRoot, -} from "@/components/workspace-notifications"; +import { NotificationItem } from "@/components/workspace-notifications"; // constants -import { NOTIFICATION_TABS, TNotificationTab } from "@/constants/notification"; -// helpers -import { cn } from "@/helpers/common.helper"; -import { getNumberCount } from "@/helpers/string.helper"; +import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification"; // hooks -import { useWorkspace, useWorkspaceNotifications } from "@/hooks/store"; +import { useWorkspaceNotifications } from "@/hooks/store"; -export const NotificationsSidebarRoot: FC = observer(() => { - const { workspaceSlug } = useParams(); - // hooks - const { getWorkspaceBySlug } = useWorkspace(); - const { - currentSelectedNotificationId, - unreadNotificationsCount, - loader, - notificationIdsByWorkspaceId, - currentNotificationTab, - setCurrentNotificationTab, - } = useWorkspaceNotifications(); - // derived values - const workspace = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString()) : undefined; - const notificationIds = workspace ? notificationIdsByWorkspaceId(workspace.id) : undefined; - - const handleTabClick = useCallback( - (tabValue: TNotificationTab) => { - if (currentNotificationTab !== tabValue) { - setCurrentNotificationTab(tabValue); - } - }, - [currentNotificationTab, setCurrentNotificationTab] - ); - - if (!workspaceSlug || !workspace) return <>; +type TNotificationCardListRoot = { + workspaceSlug: string; + workspaceId: string; +}; +export const NotificationCardListRoot: FC = observer((props) => { + const { workspaceSlug, workspaceId } = props; + // hooks + const { loader, paginationInfo, getNotifications, notificationIdsByWorkspaceId } = useWorkspaceNotifications(); + const notificationIds = notificationIdsByWorkspaceId(workspaceId); + + const getNextNotifications = async () => { + try { + await getNotifications(workspaceSlug, ENotificationLoader.PAGINATION_LOADER, ENotificationQueryParamType.NEXT); + } catch (error) { + console.error(error); + } + }; + + if (!workspaceSlug || !workspaceId || !notificationIds) return <>; return ( -
-
- - - - -
- {NOTIFICATION_TABS.map((tab) => ( -
handleTabClick(tab.value)} - > -
-
{tab.label}
- {tab.count(unreadNotificationsCount) > 0 && ( - - )} -
- {currentNotificationTab === tab.value && ( -
- )} +
+ {notificationIds.map((notificationId: string) => ( + + ))} + + {/* fetch next page notifications */} + {paginationInfo && paginationInfo?.next_page_results && ( + <> + {loader === ENotificationLoader.PAGINATION_LOADER ? ( +
+
Loading...
- ))} -
- - {/* applied filters */} - - - {/* rendering notifications */} - {loader === "init-loader" ? ( -
- -
- ) : ( - <> - {notificationIds && notificationIds.length > 0 ? ( - - - - ) : ( -
- + ) : ( +
+
+ Load more
- )} - - )} -
+
+ )} + + )}
); }); diff --git a/web/core/components/workspace-notifications/index.ts b/web/core/components/workspace-notifications/index.ts index 2682c9114fb..8bc361a7c90 100644 --- a/web/core/components/workspace-notifications/index.ts +++ b/web/core/components/workspace-notifications/index.ts @@ -1,2 +1,3 @@ export * from "./notification-app-sidebar-option"; export * from "./sidebar"; +export * from "./root"; diff --git a/web/core/components/workspace-notifications/root.tsx b/web/core/components/workspace-notifications/root.tsx new file mode 100644 index 00000000000..23236bc03b6 --- /dev/null +++ b/web/core/components/workspace-notifications/root.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { FC, useCallback } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +// components +import { Header, Row, ERowVariant, EHeaderVariant, ContentWrapper } from "@plane/ui"; +import { CountChip } from "@/components/common"; +import { + NotificationsLoader, + NotificationEmptyState, + NotificationSidebarHeader, + AppliedFilters, +} from "@/components/workspace-notifications"; +// constants +import { NOTIFICATION_TABS, TNotificationTab } from "@/constants/notification"; +// helpers +import { cn } from "@/helpers/common.helper"; +import { getNumberCount } from "@/helpers/string.helper"; +// hooks +import { useWorkspace, useWorkspaceNotifications } from "@/hooks/store"; + +import { NotificationCardListRoot } from "@/plane-web/components/workspace-notifications/root"; + +export const NotificationsSidebarRoot: FC = observer(() => { + const { workspaceSlug } = useParams(); + // hooks + const { getWorkspaceBySlug } = useWorkspace(); + const { + currentSelectedNotificationId, + unreadNotificationsCount, + loader, + notificationIdsByWorkspaceId, + currentNotificationTab, + setCurrentNotificationTab, + } = useWorkspaceNotifications(); + // derived values + const workspace = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString()) : undefined; + const notificationIds = workspace ? notificationIdsByWorkspaceId(workspace.id) : undefined; + + const handleTabClick = useCallback( + (tabValue: TNotificationTab) => { + if (currentNotificationTab !== tabValue) { + setCurrentNotificationTab(tabValue); + } + }, + [currentNotificationTab, setCurrentNotificationTab] + ); + + if (!workspaceSlug || !workspace) return <>; + + return ( +
+
+ + + + +
+ {NOTIFICATION_TABS.map((tab) => ( +
handleTabClick(tab.value)} + > +
+
{tab.label}
+ {tab.count(unreadNotificationsCount) > 0 && ( + + )} +
+ {currentNotificationTab === tab.value && ( +
+ )} +
+ ))} +
+ + {/* applied filters */} + + + {/* rendering notifications */} + {loader === "init-loader" ? ( +
+ +
+ ) : ( + <> + {notificationIds && notificationIds.length > 0 ? ( + + + + ) : ( +
+ +
+ )} + + )} +
+
+ ); +}); diff --git a/web/core/components/workspace-notifications/sidebar/notification-card/index.ts b/web/core/components/workspace-notifications/sidebar/notification-card/index.ts index d4000aa9e7f..8c086a5a81a 100644 --- a/web/core/components/workspace-notifications/sidebar/notification-card/index.ts +++ b/web/core/components/workspace-notifications/sidebar/notification-card/index.ts @@ -1,3 +1,2 @@ -export * from "./root"; export * from "./item"; export * from "./options"; diff --git a/web/core/components/workspace-notifications/sidebar/notification-card/root.tsx b/web/core/components/workspace-notifications/sidebar/notification-card/root.tsx deleted file mode 100644 index bfff113bafe..00000000000 --- a/web/core/components/workspace-notifications/sidebar/notification-card/root.tsx +++ /dev/null @@ -1,56 +0,0 @@ -"use client"; - -import { FC } from "react"; -import { observer } from "mobx-react"; -// components -import { NotificationItem } from "@/components/workspace-notifications"; -// constants -import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification"; -// hooks -import { useWorkspaceNotifications } from "@/hooks/store"; - -type TNotificationCardListRoot = { - workspaceSlug: string; - workspaceId: string; -}; - -export const NotificationCardListRoot: FC = observer((props) => { - const { workspaceSlug, workspaceId } = props; - // hooks - const { loader, paginationInfo, getNotifications, notificationIdsByWorkspaceId } = useWorkspaceNotifications(); - const notificationIds = notificationIdsByWorkspaceId(workspaceId); - - const getNextNotifications = async () => { - try { - await getNotifications(workspaceSlug, ENotificationLoader.PAGINATION_LOADER, ENotificationQueryParamType.NEXT); - } catch (error) { - console.error(error); - } - }; - - if (!workspaceSlug || !workspaceId || !notificationIds) return <>; - return ( -
- {notificationIds.map((notificationId: string) => ( - - ))} - - {/* fetch next page notifications */} - {paginationInfo && paginationInfo?.next_page_results && ( - <> - {loader === ENotificationLoader.PAGINATION_LOADER ? ( -
-
Loading...
-
- ) : ( -
-
- Load more -
-
- )} - - )} -
- ); -}); From 9b8bed496be03f71eec07f4777de0e420fb18b35 Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Tue, 10 Dec 2024 19:45:23 +0530 Subject: [PATCH 4/8] fix:notification types --- packages/types/src/workspace-notifications.d.ts | 2 +- web/core/store/notifications/notification.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/types/src/workspace-notifications.d.ts b/packages/types/src/workspace-notifications.d.ts index 7d960015b9b..0e0e15af178 100644 --- a/packages/types/src/workspace-notifications.d.ts +++ b/packages/types/src/workspace-notifications.d.ts @@ -35,7 +35,7 @@ export type TNotificationData = { }; export type TNotification = { - id: string | undefined; + id: string; title: string | undefined; data: TNotificationData | undefined; entity_identifier: string | undefined; diff --git a/web/core/store/notifications/notification.ts b/web/core/store/notifications/notification.ts index dff2755fdcb..15134a20726 100644 --- a/web/core/store/notifications/notification.ts +++ b/web/core/store/notifications/notification.ts @@ -26,7 +26,7 @@ export interface INotification extends TNotification { export class Notification implements INotification { // observables - id: string | undefined = undefined; + id: string; title: string | undefined = undefined; data: TNotificationData | undefined = undefined; entity_identifier: string | undefined = undefined; From 64c3dfd78d2cdf65bb37eeda8ff272ec049e01bd Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Tue, 10 Dec 2024 19:54:28 +0530 Subject: [PATCH 5/8] chore:file restructuring --- web/ce/components/workspace-notifications/index.ts | 2 +- .../workspace-notifications/{ => notification-card}/root.tsx | 0 web/core/components/workspace-notifications/root.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename web/ce/components/workspace-notifications/{ => notification-card}/root.tsx (100%) diff --git a/web/ce/components/workspace-notifications/index.ts b/web/ce/components/workspace-notifications/index.ts index 1efe34c51ec..18c4afa968e 100644 --- a/web/ce/components/workspace-notifications/index.ts +++ b/web/ce/components/workspace-notifications/index.ts @@ -1 +1 @@ -export * from "./root"; +export * from "./notification-card/root"; diff --git a/web/ce/components/workspace-notifications/root.tsx b/web/ce/components/workspace-notifications/notification-card/root.tsx similarity index 100% rename from web/ce/components/workspace-notifications/root.tsx rename to web/ce/components/workspace-notifications/notification-card/root.tsx diff --git a/web/core/components/workspace-notifications/root.tsx b/web/core/components/workspace-notifications/root.tsx index 23236bc03b6..fa17060d593 100644 --- a/web/core/components/workspace-notifications/root.tsx +++ b/web/core/components/workspace-notifications/root.tsx @@ -20,7 +20,7 @@ import { getNumberCount } from "@/helpers/string.helper"; // hooks import { useWorkspace, useWorkspaceNotifications } from "@/hooks/store"; -import { NotificationCardListRoot } from "@/plane-web/components/workspace-notifications/root"; +import { NotificationCardListRoot } from "@/plane-web/components/workspace-notifications"; export const NotificationsSidebarRoot: FC = observer(() => { const { workspaceSlug } = useParams(); From 5f36d9970960c4c222bb4024c66a111b2d8eac3f Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Tue, 10 Dec 2024 20:19:13 +0530 Subject: [PATCH 6/8] chore:modified notfication types --- packages/types/src/workspace-notifications.d.ts | 2 +- web/core/store/notifications/notification.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/types/src/workspace-notifications.d.ts b/packages/types/src/workspace-notifications.d.ts index 0e0e15af178..7d960015b9b 100644 --- a/packages/types/src/workspace-notifications.d.ts +++ b/packages/types/src/workspace-notifications.d.ts @@ -35,7 +35,7 @@ export type TNotificationData = { }; export type TNotification = { - id: string; + id: string | undefined; title: string | undefined; data: TNotificationData | undefined; entity_identifier: string | undefined; diff --git a/web/core/store/notifications/notification.ts b/web/core/store/notifications/notification.ts index 15134a20726..dff2755fdcb 100644 --- a/web/core/store/notifications/notification.ts +++ b/web/core/store/notifications/notification.ts @@ -26,7 +26,7 @@ export interface INotification extends TNotification { export class Notification implements INotification { // observables - id: string; + id: string | undefined = undefined; title: string | undefined = undefined; data: TNotificationData | undefined = undefined; entity_identifier: string | undefined = undefined; From 2768eaae7102ea14be1269f2eb6020810f0033a8 Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Wed, 11 Dec 2024 13:26:17 +0530 Subject: [PATCH 7/8] chore: modified types for notification --- packages/types/src/workspace-notifications.d.ts | 2 +- web/core/store/notifications/notification.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/types/src/workspace-notifications.d.ts b/packages/types/src/workspace-notifications.d.ts index 7d960015b9b..0e0e15af178 100644 --- a/packages/types/src/workspace-notifications.d.ts +++ b/packages/types/src/workspace-notifications.d.ts @@ -35,7 +35,7 @@ export type TNotificationData = { }; export type TNotification = { - id: string | undefined; + id: string; title: string | undefined; data: TNotificationData | undefined; entity_identifier: string | undefined; diff --git a/web/core/store/notifications/notification.ts b/web/core/store/notifications/notification.ts index dff2755fdcb..d2e43ba92f4 100644 --- a/web/core/store/notifications/notification.ts +++ b/web/core/store/notifications/notification.ts @@ -26,7 +26,7 @@ export interface INotification extends TNotification { export class Notification implements INotification { // observables - id: string | undefined = undefined; + id: string; title: string | undefined = undefined; data: TNotificationData | undefined = undefined; entity_identifier: string | undefined = undefined; @@ -54,6 +54,7 @@ export class Notification implements INotification { private store: CoreRootStore, private notification: TNotification ) { + this.id = this.notification.id; makeObservable(this, { // observables id: observable.ref, @@ -90,7 +91,6 @@ export class Notification implements INotification { snoozeNotification: action, unSnoozeNotification: action, }); - this.id = this.notification.id; this.title = this.notification.title; this.data = this.notification.data; this.entity_identifier = this.notification.entity_identifier; From 17d3169c1aeeca8046848e00179a273dc463018e Mon Sep 17 00:00:00 2001 From: vamsi krishna Date: Wed, 11 Dec 2024 13:38:16 +0530 Subject: [PATCH 8/8] chore:removed redundant checks for id --- web/core/store/notifications/notification.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/web/core/store/notifications/notification.ts b/web/core/store/notifications/notification.ts index d2e43ba92f4..74c0bf38cd8 100644 --- a/web/core/store/notifications/notification.ts +++ b/web/core/store/notifications/notification.ts @@ -169,8 +169,6 @@ export class Notification implements INotification { workspaceSlug: string, payload: Partial ): Promise => { - if (!this.id) return undefined; - try { const notification = await workspaceNotificationService.updateNotificationById(workspaceSlug, this.id, payload); if (notification) { @@ -188,8 +186,6 @@ export class Notification implements INotification { * @returns { TNotification | undefined } */ markNotificationAsRead = async (workspaceSlug: string): Promise => { - if (!this.id) return undefined; - const currentNotificationReadAt = this.read_at; try { const payload: Partial = { @@ -215,8 +211,6 @@ export class Notification implements INotification { * @returns { TNotification | undefined } */ markNotificationAsUnRead = async (workspaceSlug: string): Promise => { - if (!this.id) return undefined; - const currentNotificationReadAt = this.read_at; try { const payload: Partial = { @@ -242,8 +236,6 @@ export class Notification implements INotification { * @returns { TNotification | undefined } */ archiveNotification = async (workspaceSlug: string): Promise => { - if (!this.id) return undefined; - const currentNotificationArchivedAt = this.archived_at; try { const payload: Partial = { @@ -267,8 +259,6 @@ export class Notification implements INotification { * @returns { TNotification | undefined } */ unArchiveNotification = async (workspaceSlug: string): Promise => { - if (!this.id) return undefined; - const currentNotificationArchivedAt = this.archived_at; try { const payload: Partial = { @@ -293,8 +283,6 @@ export class Notification implements INotification { * @returns { TNotification | undefined } */ snoozeNotification = async (workspaceSlug: string, snoozeTill: Date): Promise => { - if (!this.id) return undefined; - const currentNotificationSnoozeTill = this.snoozed_till; try { const payload: Partial = { @@ -315,8 +303,6 @@ export class Notification implements INotification { * @returns { TNotification | undefined } */ unSnoozeNotification = async (workspaceSlug: string): Promise => { - if (!this.id) return undefined; - const currentNotificationSnoozeTill = this.snoozed_till; try { const payload: Partial = {