[WEB-1764] chore: revamp workspace notifications (#4947)

* chore: Initialised store and updated the components

* chore: updated store and types

* chore: updated notifications in the side and updated store

* chore: handled notification center

* chore: updates store request

* chore: notifications filter changed

* chore: updated filter logic and handled bulk read

* chore: handled filter dropdown

* chore: handled ui

* chore: resolved build error

* chore: implemented applied filters

* chore: removed old notifications

* chore: added redirection from sidebar

* chore: updated notification as read when we see the notification preview

* chore: updated read and unread validation

* chore: handled custom snooze dropdown

* chore: resolved git comments

* chore: updated structure and typos

* chore: import and prop changes

* chore: updated avatar props

* chore: updated avatar

* chore: notification unread count on the app sidebar

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
guru_sainath 2024-06-28 19:00:48 +05:30 committed by GitHub
parent 8d5d0422e9
commit 209dc57307
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
59 changed files with 2337 additions and 1623 deletions

View file

@ -2,7 +2,7 @@
import { linearGradientDef } from "@nivo/core";
// icons
import { BarChart2, Briefcase, CheckCircle, Home, Settings } from "lucide-react";
import { BarChart2, Bell, Briefcase, CheckCircle, Home, Settings } from "lucide-react";
// types
import { TIssuesListTypes, TStateGroups } from "@plane/types";
// ui
@ -317,4 +317,12 @@ export const SIDEBAR_USER_MENU_ITEMS: {
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/`,
Icon: Home,
},
{
key: "notifications",
label: "Notifications",
href: `/notifications`,
access: EUserWorkspaceRoles.GUEST,
highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/notifications`,
Icon: Bell,
},
];

View file

@ -80,6 +80,8 @@ export enum EmptyStateType {
ISSUE_RELATION_EMPTY_STATE = "issue-relation-empty-state",
ISSUE_COMMENT_EMPTY_STATE = "issue-comment-empty-state",
NOTIFICATION_ALL_EMPTY_STATE = "notification-all-empty-state",
NOTIFICATION_MENTIONS_EMPTY_STATE = "notification-mentions-empty-state",
NOTIFICATION_MY_ISSUE_EMPTY_STATE = "notification-my-issues-empty-state",
NOTIFICATION_CREATED_EMPTY_STATE = "notification-created-empty-state",
NOTIFICATION_SUBSCRIBED_EMPTY_STATE = "notification-subscribed-empty-state",
@ -593,13 +595,24 @@ const emptyStateDetails = {
path: "/empty-state/search/comments",
},
[EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE]: {
key: EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE,
title: "No issues assigned",
description: "Updates for issues assigned to you can be \n seen here",
path: "/empty-state/search/notification",
},
[EmptyStateType.NOTIFICATION_MENTIONS_EMPTY_STATE]: {
key: EmptyStateType.NOTIFICATION_MENTIONS_EMPTY_STATE,
title: "No issues assigned",
description: "Updates for issues assigned to you can be \n seen here",
path: "/empty-state/search/notification",
},
[EmptyStateType.NOTIFICATION_MY_ISSUE_EMPTY_STATE]: {
key: EmptyStateType.NOTIFICATION_MY_ISSUE_EMPTY_STATE,
title: "No issues assigned",
description: "Updates for issues assigned to you can be \n seen here",
path: "/empty-state/search/notification",
},
[EmptyStateType.NOTIFICATION_CREATED_EMPTY_STATE]: {
key: EmptyStateType.NOTIFICATION_CREATED_EMPTY_STATE,
title: "No updates to issues",
@ -630,6 +643,7 @@ const emptyStateDetails = {
description: "Any notification you archive will be \n available here to help you focus",
path: "/empty-state/search/archive",
},
[EmptyStateType.ACTIVE_CYCLE_PROGRESS_EMPTY_STATE]: {
key: EmptyStateType.ACTIVE_CYCLE_PROGRESS_EMPTY_STATE,
title: "Add issues to the cycle to view it's \n progress",

View file

@ -1,5 +1,4 @@
import { IAnalyticsParams, IJiraMetadata, INotificationParams } from "@plane/types";
import { objToQueryParams } from "@/helpers/string.helper";
import { IAnalyticsParams, IJiraMetadata } from "@plane/types";
const paramsToKey = (params: any) => {
const {
@ -246,41 +245,6 @@ export const ANALYTICS = (workspaceSlug: string, params: IAnalyticsParams) =>
export const DEFAULT_ANALYTICS = (workspaceSlug: string, params?: Partial<IAnalyticsParams>) =>
`DEFAULT_ANALYTICS_${workspaceSlug.toUpperCase()}_${params?.project?.toString()}_${params?.cycle}_${params?.module}`;
// notifications
export const USER_WORKSPACE_NOTIFICATIONS = (workspaceSlug: string, params: INotificationParams) => {
const { type, snoozed, archived, read } = params;
return `USER_WORKSPACE_NOTIFICATIONS_${workspaceSlug?.toUpperCase()}_TYPE_${(
type ?? "assigned"
)?.toUpperCase()}_SNOOZED_${snoozed}_ARCHIVED_${archived}_READ_${read}`;
};
export const USER_WORKSPACE_NOTIFICATIONS_DETAILS = (workspaceSlug: string, notificationId: string) =>
`USER_WORKSPACE_NOTIFICATIONS_DETAILS_${workspaceSlug?.toUpperCase()}_${notificationId?.toUpperCase()}`;
export const UNREAD_NOTIFICATIONS_COUNT = (workspaceSlug: string) =>
`UNREAD_NOTIFICATIONS_COUNT_${workspaceSlug?.toUpperCase()}`;
export const getPaginatedNotificationKey = (index: number, prevData: any, workspaceSlug: string, params: any) => {
if (prevData && !prevData?.results?.length) return null;
if (index === 0)
return `/api/workspaces/${workspaceSlug}/users/notifications?${objToQueryParams({
...params,
cursor: "30:0:0",
})}`;
const cursor = prevData?.next_cursor;
const nextPageResults = prevData?.next_page_results;
if (!nextPageResults) return null;
return `/api/workspaces/${workspaceSlug}/users/notifications?${objToQueryParams({
...params,
cursor,
})}`;
};
// profile
export const USER_PROFILE_DATA = (workspaceSlug: string, userId: string) =>
`USER_PROFILE_ACTIVITY_${workspaceSlug.toUpperCase()}_${userId.toUpperCase()}`;

View file

@ -1,27 +1,101 @@
export const snoozeOptions = [
export enum ENotificationTab {
ALL = "all",
MENTIONS = "mentions",
}
export enum ENotificationFilterType {
CREATED = "created",
ASSIGNED = "assigned",
SUBSCRIBED = "subscribed",
}
export enum ENotificationLoader {
INIT_LOADER = "init-loader",
MUTATION_LOADER = "mutation-loader",
PAGINATION_LOADER = "pagination-loader",
REFRESH = "refresh",
MARK_ALL_AS_READY = "mark-all-as-read",
}
export enum ENotificationQueryParamType {
INIT = "init",
CURRENT = "current",
NEXT = "next",
}
export type TNotificationTab = ENotificationTab.ALL | ENotificationTab.MENTIONS;
export const NOTIFICATION_TABS = [
{
label: "All",
value: ENotificationTab.ALL,
},
// {
// label: "Mentions",
// value: ENotificationTab.MENTIONS,
// },
];
export const FILTER_TYPE_OPTIONS = [
{
label: "Assigned to me",
value: ENotificationFilterType.ASSIGNED,
},
{
label: "Created by me",
value: ENotificationFilterType.CREATED,
},
{
label: "Subscribed by me",
value: ENotificationFilterType.SUBSCRIBED,
},
];
export const NOTIFICATION_SNOOZE_OPTIONS = [
{
key: "1_day",
label: "1 day",
value: new Date(new Date().getTime() + 24 * 60 * 60 * 1000),
value: () => {
const date = new Date();
return new Date(date.getTime() + 24 * 60 * 60 * 1000);
},
},
{
key: "3_days",
label: "3 days",
value: new Date(new Date().getTime() + 3 * 24 * 60 * 60 * 1000),
value: () => {
const date = new Date();
return new Date(date.getTime() + 3 * 24 * 60 * 60 * 1000);
},
},
{
key: "5_days",
label: "5 days",
value: new Date(new Date().getTime() + 5 * 24 * 60 * 60 * 1000),
value: () => {
const date = new Date();
return new Date(date.getTime() + 5 * 24 * 60 * 60 * 1000);
},
},
{
key: "1_week",
label: "1 week",
value: new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000),
value: () => {
const date = new Date();
return new Date(date.getTime() + 7 * 24 * 60 * 60 * 1000);
},
},
{
key: "2_weeks",
label: "2 weeks",
value: new Date(new Date().getTime() + 14 * 24 * 60 * 60 * 1000),
value: () => {
const date = new Date();
return new Date(date.getTime() + 14 * 24 * 60 * 60 * 1000);
},
},
{
key: "custom",
label: "Custom",
value: null,
value: undefined,
},
];