2023-07-26 06:32:14 +00:00
|
|
|
import React from "react";
|
2023-10-16 14:57:22 +00:00
|
|
|
import { ArrowLeft, CheckCheck, Clock, ListFilter, MoreVertical, RefreshCw, X } from "lucide-react";
|
2024-03-19 14:38:35 +00:00
|
|
|
import type { NotificationType, NotificationCount } from "@plane/types";
|
2024-02-09 10:47:39 +00:00
|
|
|
// components
|
2024-03-06 13:09:14 +00:00
|
|
|
import { ArchiveIcon, CustomMenu, Tooltip } from "@plane/ui";
|
2024-03-19 14:38:35 +00:00
|
|
|
import { SidebarHamburgerToggle } from "@/components/core/sidebar/sidebar-menu-hamburger-toggle";
|
2023-11-03 13:51:35 +00:00
|
|
|
// ui
|
2024-02-09 10:52:08 +00:00
|
|
|
// hooks
|
|
|
|
import {
|
|
|
|
ARCHIVED_NOTIFICATIONS,
|
|
|
|
NOTIFICATIONS_READ,
|
|
|
|
SNOOZED_NOTIFICATIONS,
|
|
|
|
UNREAD_NOTIFICATIONS,
|
2024-03-19 14:38:35 +00:00
|
|
|
} from "@/constants/event-tracker";
|
|
|
|
import { getNumberCount } from "@/helpers/string.helper";
|
|
|
|
import { useEventTracker } from "@/hooks/store";
|
|
|
|
import { usePlatformOS } from "@/hooks/use-platform-os";
|
2024-03-06 13:09:14 +00:00
|
|
|
// helpers
|
|
|
|
// type
|
|
|
|
// constants
|
2023-07-26 06:32:14 +00:00
|
|
|
|
|
|
|
type NotificationHeaderProps = {
|
|
|
|
notificationCount?: NotificationCount | null;
|
|
|
|
notificationMutate: () => void;
|
|
|
|
closePopover: () => void;
|
|
|
|
isRefreshing?: boolean;
|
|
|
|
snoozed: boolean;
|
|
|
|
archived: boolean;
|
|
|
|
readNotification: boolean;
|
|
|
|
selectedTab: NotificationType;
|
|
|
|
setSnoozed: React.Dispatch<React.SetStateAction<boolean>>;
|
|
|
|
setArchived: React.Dispatch<React.SetStateAction<boolean>>;
|
|
|
|
setReadNotification: React.Dispatch<React.SetStateAction<boolean>>;
|
|
|
|
setSelectedTab: React.Dispatch<React.SetStateAction<NotificationType>>;
|
2023-08-28 07:56:38 +00:00
|
|
|
markAllNotificationsAsRead: () => Promise<void>;
|
2023-07-26 06:32:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export const NotificationHeader: React.FC<NotificationHeaderProps> = (props) => {
|
|
|
|
const {
|
|
|
|
notificationCount,
|
|
|
|
notificationMutate,
|
|
|
|
closePopover,
|
|
|
|
isRefreshing,
|
|
|
|
snoozed,
|
|
|
|
archived,
|
|
|
|
readNotification,
|
|
|
|
selectedTab,
|
|
|
|
setSnoozed,
|
|
|
|
setArchived,
|
|
|
|
setReadNotification,
|
|
|
|
setSelectedTab,
|
2023-08-28 07:56:38 +00:00
|
|
|
markAllNotificationsAsRead,
|
2023-07-26 06:32:14 +00:00
|
|
|
} = props;
|
2024-02-09 10:52:08 +00:00
|
|
|
// store hooks
|
|
|
|
const { captureEvent } = useEventTracker();
|
2024-03-12 15:09:36 +00:00
|
|
|
// hooks
|
|
|
|
const { isMobile } = usePlatformOS();
|
2023-07-26 06:32:14 +00:00
|
|
|
|
|
|
|
const notificationTabs: Array<{
|
|
|
|
label: string;
|
|
|
|
value: NotificationType;
|
|
|
|
unreadCount?: number;
|
|
|
|
}> = [
|
|
|
|
{
|
|
|
|
label: "My Issues",
|
|
|
|
value: "assigned",
|
|
|
|
unreadCount: notificationCount?.my_issues,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: "Created by me",
|
|
|
|
value: "created",
|
|
|
|
unreadCount: notificationCount?.created_issues,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: "Subscribed",
|
|
|
|
value: "watching",
|
|
|
|
unreadCount: notificationCount?.watching_issues,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div className="flex items-center justify-between px-5 pt-5">
|
2024-02-09 10:47:39 +00:00
|
|
|
<div className="flex items-center gap-x-2 ">
|
|
|
|
<SidebarHamburgerToggle />
|
|
|
|
<h2 className="md:text-xl md:font-semibold">Notifications</h2>
|
|
|
|
</div>
|
|
|
|
|
2023-12-10 10:18:10 +00:00
|
|
|
<div className="flex items-center justify-center gap-x-4 text-custom-text-200">
|
2024-03-12 15:09:36 +00:00
|
|
|
<Tooltip tooltipContent="Refresh" isMobile={isMobile}>
|
2023-07-26 06:32:14 +00:00
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
onClick={() => {
|
|
|
|
notificationMutate();
|
|
|
|
}}
|
|
|
|
>
|
2023-10-16 14:57:22 +00:00
|
|
|
<RefreshCw className={`h-3.5 w-3.5 ${isRefreshing ? "animate-spin" : ""}`} />
|
2023-07-26 06:32:14 +00:00
|
|
|
</button>
|
|
|
|
</Tooltip>
|
2024-03-12 15:09:36 +00:00
|
|
|
<Tooltip tooltipContent="Unread notifications" isMobile={isMobile}>
|
2023-07-26 06:32:14 +00:00
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
onClick={() => {
|
|
|
|
setSnoozed(false);
|
|
|
|
setArchived(false);
|
|
|
|
setReadNotification((prev) => !prev);
|
2024-02-09 10:52:08 +00:00
|
|
|
captureEvent(UNREAD_NOTIFICATIONS);
|
2023-07-26 06:32:14 +00:00
|
|
|
}}
|
|
|
|
>
|
2023-10-16 14:57:22 +00:00
|
|
|
<ListFilter className="h-3.5 w-3.5" />
|
2023-07-26 06:32:14 +00:00
|
|
|
</button>
|
|
|
|
</Tooltip>
|
2023-08-28 07:56:38 +00:00
|
|
|
<CustomMenu
|
|
|
|
customButton={
|
|
|
|
<div className="grid place-items-center ">
|
2023-10-16 14:57:22 +00:00
|
|
|
<MoreVertical className="h-3.5 w-3.5" />
|
2023-08-28 07:56:38 +00:00
|
|
|
</div>
|
|
|
|
}
|
2024-01-29 11:56:48 +00:00
|
|
|
closeOnSelect
|
2023-08-28 07:56:38 +00:00
|
|
|
>
|
2024-02-09 10:52:08 +00:00
|
|
|
<CustomMenu.MenuItem
|
|
|
|
onClick={() => {
|
|
|
|
markAllNotificationsAsRead();
|
|
|
|
captureEvent(NOTIFICATIONS_READ);
|
|
|
|
}}
|
|
|
|
>
|
2023-08-28 07:56:38 +00:00
|
|
|
<div className="flex items-center gap-2">
|
2023-10-16 14:57:22 +00:00
|
|
|
<CheckCheck className="h-3.5 w-3.5" />
|
2023-08-28 07:56:38 +00:00
|
|
|
Mark all as read
|
|
|
|
</div>
|
|
|
|
</CustomMenu.MenuItem>
|
|
|
|
<CustomMenu.MenuItem
|
2023-07-26 06:32:14 +00:00
|
|
|
onClick={() => {
|
|
|
|
setArchived(false);
|
|
|
|
setReadNotification(false);
|
|
|
|
setSnoozed((prev) => !prev);
|
2024-02-09 10:52:08 +00:00
|
|
|
captureEvent(SNOOZED_NOTIFICATIONS);
|
2023-07-26 06:32:14 +00:00
|
|
|
}}
|
|
|
|
>
|
2023-08-28 07:56:38 +00:00
|
|
|
<div className="flex items-center gap-2">
|
2023-10-16 14:57:22 +00:00
|
|
|
<Clock className="h-3.5 w-3.5" />
|
2023-08-28 07:56:38 +00:00
|
|
|
Show snoozed
|
|
|
|
</div>
|
|
|
|
</CustomMenu.MenuItem>
|
|
|
|
<CustomMenu.MenuItem
|
2023-07-26 06:32:14 +00:00
|
|
|
onClick={() => {
|
|
|
|
setSnoozed(false);
|
|
|
|
setReadNotification(false);
|
|
|
|
setArchived((prev) => !prev);
|
2024-02-09 10:52:08 +00:00
|
|
|
captureEvent(ARCHIVED_NOTIFICATIONS);
|
2023-07-26 06:32:14 +00:00
|
|
|
}}
|
|
|
|
>
|
2023-08-28 07:56:38 +00:00
|
|
|
<div className="flex items-center gap-2">
|
2023-10-16 14:57:22 +00:00
|
|
|
<ArchiveIcon className="h-3.5 w-3.5" />
|
2023-08-28 07:56:38 +00:00
|
|
|
Show archived
|
|
|
|
</div>
|
|
|
|
</CustomMenu.MenuItem>
|
|
|
|
</CustomMenu>
|
2024-02-09 10:47:39 +00:00
|
|
|
<div className="hidden md:block">
|
2024-03-12 15:09:36 +00:00
|
|
|
<Tooltip tooltipContent="Close" isMobile={isMobile}>
|
2024-02-09 10:47:39 +00:00
|
|
|
<button type="button" onClick={() => closePopover()}>
|
|
|
|
<X className="h-3.5 w-3.5" />
|
|
|
|
</button>
|
|
|
|
</Tooltip>
|
|
|
|
</div>
|
2023-07-26 06:32:14 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2023-12-10 10:18:10 +00:00
|
|
|
<div className="mt-5 w-full border-b border-custom-border-300 px-5">
|
2023-07-26 06:32:14 +00:00
|
|
|
{snoozed || archived || readNotification ? (
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
onClick={() => {
|
|
|
|
setSnoozed(false);
|
|
|
|
setArchived(false);
|
|
|
|
setReadNotification(false);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<h4 className="flex items-center gap-2 pb-4">
|
2023-10-16 14:57:22 +00:00
|
|
|
<ArrowLeft className="h-3.5 w-3.5" />
|
2023-07-26 06:32:14 +00:00
|
|
|
<span className="ml-2 font-medium">
|
|
|
|
{snoozed
|
|
|
|
? "Snoozed Notifications"
|
|
|
|
: readNotification
|
2024-03-06 13:09:14 +00:00
|
|
|
? "Unread Notifications"
|
|
|
|
: "Archived Notifications"}
|
2023-07-26 06:32:14 +00:00
|
|
|
</span>
|
|
|
|
</h4>
|
|
|
|
</button>
|
|
|
|
) : (
|
|
|
|
<nav className="flex space-x-5 overflow-x-auto" aria-label="Tabs">
|
2023-08-01 08:00:51 +00:00
|
|
|
{notificationTabs.map((tab) => (
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
key={tab.value}
|
|
|
|
onClick={() => setSelectedTab(tab.value)}
|
2023-12-10 10:18:10 +00:00
|
|
|
className={`whitespace-nowrap border-b-2 px-1 pb-4 text-sm font-medium outline-none ${
|
2023-08-01 08:00:51 +00:00
|
|
|
tab.value === selectedTab
|
|
|
|
? "border-custom-primary-100 text-custom-primary-100"
|
|
|
|
: "border-transparent text-custom-text-200"
|
|
|
|
}`}
|
|
|
|
>
|
|
|
|
{tab.label}
|
|
|
|
{tab.unreadCount && tab.unreadCount > 0 ? (
|
|
|
|
<span
|
2023-12-10 10:18:10 +00:00
|
|
|
className={`ml-2 rounded-full px-2 py-0.5 text-xs ${
|
2023-07-26 06:32:14 +00:00
|
|
|
tab.value === selectedTab
|
2023-08-01 08:00:51 +00:00
|
|
|
? "bg-custom-primary-100 text-white"
|
|
|
|
: "bg-custom-background-80 text-custom-text-200"
|
2023-07-26 06:32:14 +00:00
|
|
|
}`}
|
|
|
|
>
|
2023-08-01 08:00:51 +00:00
|
|
|
{getNumberCount(tab.unreadCount)}
|
|
|
|
</span>
|
|
|
|
) : null}
|
|
|
|
</button>
|
|
|
|
))}
|
2023-07-26 06:32:14 +00:00
|
|
|
</nav>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
};
|