[WEB-1916] ui: updated the empty state design in workspace notifications and ui changes (#5093)
* ui: updated the empty state design in workspace notifications and ui changes * chore: updated the popover custom components * ui: updated the badge ui on the sidrbar options * ui: broken down the menu components
This commit is contained in:
parent
a90724516b
commit
2136872351
13 changed files with 263 additions and 266 deletions
|
|
@ -6,9 +6,11 @@ import useSWR from "swr";
|
|||
// components
|
||||
import { LogoSpinner } from "@/components/common";
|
||||
import { PageHead } from "@/components/core";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
import { InboxContentRoot } from "@/components/inbox";
|
||||
import { IssuePeekOverview } from "@/components/issues";
|
||||
// constants
|
||||
import { EmptyStateType } from "@/constants/empty-state";
|
||||
import { ENotificationLoader, ENotificationQueryParamType } from "@/constants/notification";
|
||||
// hooks
|
||||
import { useIssueDetail, useUser, useWorkspace, useWorkspaceNotifications } from "@/hooks/store";
|
||||
|
|
@ -62,36 +64,44 @@ const WorkspaceDashboardPage = observer(() => {
|
|||
setCurrentSelectedNotificationId(undefined);
|
||||
setPeekIssue(undefined);
|
||||
},
|
||||
[]
|
||||
[setCurrentSelectedNotificationId, setPeekIssue]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<div className="w-full h-full overflow-hidden overflow-y-auto">
|
||||
{is_inbox_issue === true && workspace_slug && project_id && issue_id ? (
|
||||
{!currentSelectedNotificationId ? (
|
||||
<div className="w-full h-screen flex justify-center items-center">
|
||||
<EmptyState type={EmptyStateType.NOTIFICATION_DETAIL_EMPTY_STATE} layout="screen-simple" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{projectMemberInfoLoader ? (
|
||||
<div className="w-full h-full flex justify-center items-center">
|
||||
<LogoSpinner />
|
||||
</div>
|
||||
{is_inbox_issue === true && workspace_slug && project_id && issue_id ? (
|
||||
<>
|
||||
{projectMemberInfoLoader ? (
|
||||
<div className="w-full h-full flex justify-center items-center">
|
||||
<LogoSpinner />
|
||||
</div>
|
||||
) : (
|
||||
<InboxContentRoot
|
||||
setIsMobileSidebar={() => {}}
|
||||
isMobileSidebar={false}
|
||||
workspaceSlug={workspace_slug}
|
||||
projectId={project_id}
|
||||
inboxIssueId={issue_id}
|
||||
isNotificationEmbed
|
||||
embedRemoveCurrentNotification={() => setCurrentSelectedNotificationId(undefined)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<InboxContentRoot
|
||||
setIsMobileSidebar={() => {}}
|
||||
isMobileSidebar={false}
|
||||
workspaceSlug={workspace_slug}
|
||||
projectId={project_id}
|
||||
inboxIssueId={issue_id}
|
||||
isNotificationEmbed
|
||||
<IssuePeekOverview
|
||||
embedIssue
|
||||
embedRemoveCurrentNotification={() => setCurrentSelectedNotificationId(undefined)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<IssuePeekOverview
|
||||
embedIssue
|
||||
embedRemoveCurrentNotification={() => setCurrentSelectedNotificationId(undefined)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export const NotificationAppSidebarOption: FC<TNotificationAppSidebarOption> = o
|
|||
|
||||
return (
|
||||
<div className="ml-auto">
|
||||
<CountChip count={`${isMentionsEnabled ? `@` : ``}${getNumberCount(totalNotifications)}`} />
|
||||
<CountChip count={`${isMentionsEnabled ? `@ ` : ``}${getNumberCount(totalNotifications)}`} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
export * from "./root";
|
||||
export * from "./menu";
|
||||
export * from "./applied-filter";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./root";
|
||||
export * from "./menu-option-item";
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check } from "lucide-react";
|
||||
// constants
|
||||
import { ENotificationFilterType } from "@/constants/notification";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useWorkspaceNotifications } from "@/hooks/store";
|
||||
|
||||
export const NotificationFilterOptionItem: FC<{ label: string; value: ENotificationFilterType }> = observer((props) => {
|
||||
const { value, label } = props;
|
||||
// hooks
|
||||
const { filters, updateFilters } = useWorkspaceNotifications();
|
||||
|
||||
const handleFilterTypeChange = (filterType: ENotificationFilterType, filterValue: boolean) =>
|
||||
updateFilters("type", {
|
||||
...filters.type,
|
||||
[filterType]: filterValue,
|
||||
});
|
||||
|
||||
// derived values
|
||||
const isSelected = filters?.type?.[value] || false;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={value}
|
||||
className="flex items-center gap-2 cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() => handleFilterTypeChange(value, !isSelected)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex-shrink-0 w-3 h-3 flex justify-center items-center rounded-sm transition-all",
|
||||
isSelected ? "bg-custom-primary-100" : "bg-custom-background-90"
|
||||
)}
|
||||
>
|
||||
{isSelected && <Check className="h-2 w-2" />}
|
||||
</div>
|
||||
<div className={cn("whitespace-nowrap text-sm", isSelected ? "text-custom-text-100" : "text-custom-text-200")}>
|
||||
{label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { ListFilter } from "lucide-react";
|
||||
import { PopoverMenu, Tooltip } from "@plane/ui";
|
||||
// components
|
||||
import { NotificationFilterOptionItem } from "@/components/workspace-notifications";
|
||||
// constants
|
||||
import { ENotificationFilterType, FILTER_TYPE_OPTIONS } from "@/constants/notification";
|
||||
// hooks
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
export const NotificationFilter: FC = observer(() => {
|
||||
// hooks
|
||||
const { isMobile } = usePlatformOS();
|
||||
|
||||
return (
|
||||
<PopoverMenu
|
||||
data={FILTER_TYPE_OPTIONS}
|
||||
button={
|
||||
<Tooltip tooltipContent="Notification Filters" 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 outline-none">
|
||||
<ListFilter className="h-3 w-3" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
keyExtractor={(item: { label: string; value: ENotificationFilterType }) => item.value}
|
||||
render={(item) => <NotificationFilterOptionItem {...item} />}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import { FC, Fragment } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check, ListFilter } from "lucide-react";
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
import { Tooltip } from "@plane/ui";
|
||||
// constants
|
||||
import { ENotificationFilterType, FILTER_TYPE_OPTIONS } from "@/constants/notification";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useWorkspaceNotifications } from "@/hooks/store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
export const NotificationFilter: FC = observer(() => {
|
||||
// hooks
|
||||
const { isMobile } = usePlatformOS();
|
||||
const { filters, updateFilters } = useWorkspaceNotifications();
|
||||
|
||||
const handleFilterTypeChange = (filterType: ENotificationFilterType, filterValue: boolean) =>
|
||||
updateFilters("type", {
|
||||
...filters.type,
|
||||
[filterType]: filterValue,
|
||||
});
|
||||
|
||||
return (
|
||||
<Popover className="relative">
|
||||
<Tooltip tooltipContent="Notification Filters" isMobile={isMobile} position="bottom">
|
||||
<Popover.Button
|
||||
className={cn(
|
||||
"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 outline-none",
|
||||
({ open }: { open: boolean }) => (open ? "bg-custom-background-80" : "")
|
||||
)}
|
||||
>
|
||||
<ListFilter className="h-3 w-3" />
|
||||
</Popover.Button>
|
||||
</Tooltip>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1"
|
||||
>
|
||||
<Popover.Panel className="absolute mt-2 right-0 z-10 min-w-44">
|
||||
<div className="p-2 rounded-md border border-custom-border-200 bg-custom-background-100">
|
||||
{FILTER_TYPE_OPTIONS.map((filter) => {
|
||||
const isSelected = filters?.type?.[filter?.value] || false;
|
||||
return (
|
||||
<div
|
||||
key={filter.value}
|
||||
className="flex items-center gap-2 cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() => handleFilterTypeChange(filter?.value, !isSelected)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex-shrink-0 w-3 h-3 flex justify-center items-center rounded-sm transition-all",
|
||||
isSelected ? "bg-custom-primary-100" : "bg-custom-background-90"
|
||||
)}
|
||||
>
|
||||
{isSelected && <Check className="h-2 w-2" />}
|
||||
</div>
|
||||
<div
|
||||
className={cn("whitespace-nowrap", isSelected ? "text-custom-text-100" : "text-custom-text-200")}
|
||||
>
|
||||
{filter.label}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</Popover>
|
||||
);
|
||||
});
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import { FC, Fragment } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check, CheckCheck, CheckCircle, Clock, MoreVertical } from "lucide-react";
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
import { TNotificationFilter } from "@plane/types";
|
||||
import { ArchiveIcon, Spinner, Tooltip } from "@plane/ui";
|
||||
// constants
|
||||
import { NOTIFICATIONS_READ } from "@/constants/event-tracker";
|
||||
import { ENotificationLoader } from "@/constants/notification";
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useEventTracker, useWorkspaceNotifications } from "@/hooks/store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
type TNotificationHeaderMenuOption = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const NotificationHeaderMenuOption: FC<TNotificationHeaderMenuOption> = observer((props) => {
|
||||
const { workspaceSlug } = props;
|
||||
// hooks
|
||||
const { captureEvent } = useEventTracker();
|
||||
const { isMobile } = usePlatformOS();
|
||||
const { loader, filters, updateFilters, updateBulkFilters, markAllNotificationsAsRead } = useWorkspaceNotifications();
|
||||
|
||||
const handleFilterChange = (filterType: keyof TNotificationFilter, filterValue: boolean) =>
|
||||
updateFilters(filterType, filterValue);
|
||||
|
||||
const handleBulkFilterChange = (filter: Partial<TNotificationFilter>) => updateBulkFilters(filter);
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover className="relative">
|
||||
<Tooltip tooltipContent="Notification Filters" isMobile={isMobile} position="bottom">
|
||||
<Popover.Button
|
||||
className={cn(
|
||||
"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 outline-none",
|
||||
({ open }: { open: boolean }) => (open ? "bg-custom-background-80" : "")
|
||||
)}
|
||||
>
|
||||
<MoreVertical className="h-3 w-3" />
|
||||
</Popover.Button>
|
||||
</Tooltip>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1"
|
||||
>
|
||||
<Popover.Panel className="absolute mt-2 right-0 z-10 min-w-44 select-none">
|
||||
<div className="py-2 rounded-md border border-custom-border-200 bg-custom-background-100 space-y-1">
|
||||
<div className="px-2">
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() => {
|
||||
handleMarkAllNotificationsAsRead();
|
||||
captureEvent(NOTIFICATIONS_READ);
|
||||
}}
|
||||
>
|
||||
<CheckCheck className="h-3 w-3" />
|
||||
<div>Mark all as read</div>
|
||||
{loader === ENotificationLoader.MARK_ALL_AS_READY && (
|
||||
<div className="ml-auto">
|
||||
<Spinner height="14px" width="14px" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-b border-custom-border-200 " />
|
||||
|
||||
<div className="px-2">
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() => handleFilterChange("read", !filters?.read)}
|
||||
>
|
||||
<CheckCircle className="flex-shrink-0 h-3 w-3" />
|
||||
<div
|
||||
className={cn("whitespace-nowrap", filters?.read ? "text-custom-text-100" : "text-custom-text-200")}
|
||||
>
|
||||
Show unread
|
||||
</div>
|
||||
{filters?.read && (
|
||||
<div className="ml-auto">
|
||||
<Check className="w-3 h-3" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() =>
|
||||
handleBulkFilterChange({
|
||||
archived: !filters?.archived,
|
||||
snoozed: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<ArchiveIcon className="flex-shrink-0 h-3 w-3" />
|
||||
<div
|
||||
className={cn(
|
||||
"whitespace-nowrap",
|
||||
filters?.archived ? "text-custom-text-100" : "text-custom-text-200"
|
||||
)}
|
||||
>
|
||||
Show Archived
|
||||
</div>
|
||||
{filters?.archived && (
|
||||
<div className="ml-auto">
|
||||
<Check className="w-3 h-3" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() =>
|
||||
handleBulkFilterChange({
|
||||
snoozed: !filters?.snoozed,
|
||||
archived: false,
|
||||
})
|
||||
}
|
||||
>
|
||||
<Clock className="flex-shrink-0 h-3 w-3" />
|
||||
<div
|
||||
className={cn(
|
||||
"whitespace-nowrap",
|
||||
filters?.snoozed ? "text-custom-text-100" : "text-custom-text-200"
|
||||
)}
|
||||
>
|
||||
Show Snoozed
|
||||
</div>
|
||||
{filters?.snoozed && (
|
||||
<div className="ml-auto">
|
||||
<Check className="w-3 h-3" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</Popover>
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./root";
|
||||
export * from "./menu-item";
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
import type { TPopoverMenuOptions } from "@/components/workspace-notifications";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
|
||||
export const NotificationMenuOptionItem: FC<TPopoverMenuOptions> = observer((props) => {
|
||||
const { type, label = "", isActive, prependIcon, appendIcon, onClick } = props;
|
||||
|
||||
if (type === "menu-item")
|
||||
return (
|
||||
<div
|
||||
className="flex items-center gap-2 cursor-pointer mx-2 px-2 p-1 transition-all hover:bg-custom-background-80 rounded-sm"
|
||||
onClick={() => onClick && onClick()}
|
||||
>
|
||||
{prependIcon && prependIcon}
|
||||
<div className={cn("whitespace-nowrap text-sm", isActive ? "text-custom-text-100" : "text-custom-text-200")}>
|
||||
{label}
|
||||
</div>
|
||||
{appendIcon && <div className="ml-auto">{appendIcon}</div>}
|
||||
</div>
|
||||
);
|
||||
|
||||
return <div className="border-b border-custom-border-200" />;
|
||||
});
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
"use client";
|
||||
|
||||
import { FC, ReactNode } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Check, CheckCheck, CheckCircle, Clock } from "lucide-react";
|
||||
import { TNotificationFilter } from "@plane/types";
|
||||
import { ArchiveIcon, PopoverMenu, Spinner } from "@plane/ui";
|
||||
// components
|
||||
import { NotificationMenuOptionItem } from "@/components/workspace-notifications";
|
||||
// constants
|
||||
import { NOTIFICATIONS_READ } from "@/constants/event-tracker";
|
||||
import { ENotificationLoader } from "@/constants/notification";
|
||||
// hooks
|
||||
import { useEventTracker, useWorkspaceNotifications } from "@/hooks/store";
|
||||
|
||||
type TNotificationHeaderMenuOption = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export type TPopoverMenuOptions = {
|
||||
key: string;
|
||||
type: string;
|
||||
label?: string | undefined;
|
||||
isActive?: boolean | undefined;
|
||||
prependIcon?: ReactNode | undefined;
|
||||
appendIcon?: ReactNode | undefined;
|
||||
onClick?: (() => void) | undefined;
|
||||
};
|
||||
|
||||
export const NotificationHeaderMenuOption: FC<TNotificationHeaderMenuOption> = observer((props) => {
|
||||
const { workspaceSlug } = props;
|
||||
// hooks
|
||||
const { captureEvent } = useEventTracker();
|
||||
const { loader, filters, updateFilters, updateBulkFilters, markAllNotificationsAsRead } = useWorkspaceNotifications();
|
||||
|
||||
const handleFilterChange = (filterType: keyof TNotificationFilter, filterValue: boolean) =>
|
||||
updateFilters(filterType, filterValue);
|
||||
|
||||
const handleBulkFilterChange = (filter: Partial<TNotificationFilter>) => updateBulkFilters(filter);
|
||||
|
||||
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 popoverMenuOptions: TPopoverMenuOptions[] = [
|
||||
{
|
||||
key: "menu-mark-all-read",
|
||||
type: "menu-item",
|
||||
label: "Mark all as read",
|
||||
isActive: true,
|
||||
prependIcon: <CheckCheck className="h-3 w-3" />,
|
||||
appendIcon: loader === ENotificationLoader.MARK_ALL_AS_READY ? <Spinner height="14px" width="14px" /> : undefined,
|
||||
onClick: () => {
|
||||
captureEvent(NOTIFICATIONS_READ);
|
||||
handleMarkAllNotificationsAsRead();
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "menu-divider",
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
key: "menu-unread",
|
||||
type: "menu-item",
|
||||
label: "Show unread",
|
||||
isActive: filters?.read,
|
||||
prependIcon: <CheckCircle className="flex-shrink-0 h-3 w-3" />,
|
||||
appendIcon: filters?.read ? <Check className="w-3 h-3" /> : undefined,
|
||||
onClick: () => handleFilterChange("read", !filters?.read),
|
||||
},
|
||||
{
|
||||
key: "menu-archived",
|
||||
type: "menu-item",
|
||||
label: "Show archived",
|
||||
isActive: filters?.archived,
|
||||
prependIcon: <ArchiveIcon className="flex-shrink-0 h-3 w-3" />,
|
||||
appendIcon: filters?.archived ? <Check className="w-3 h-3" /> : undefined,
|
||||
onClick: () =>
|
||||
handleBulkFilterChange({
|
||||
archived: !filters?.archived,
|
||||
snoozed: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: "menu-snoozed",
|
||||
type: "menu-item",
|
||||
label: "Show snoozed",
|
||||
isActive: filters?.snoozed,
|
||||
prependIcon: <Clock className="flex-shrink-0 h-3 w-3" />,
|
||||
appendIcon: filters?.snoozed ? <Check className="w-3 h-3" /> : undefined,
|
||||
onClick: () =>
|
||||
handleBulkFilterChange({
|
||||
snoozed: !filters?.snoozed,
|
||||
archived: false,
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PopoverMenu
|
||||
data={popoverMenuOptions}
|
||||
buttonClassName="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 outline-none"
|
||||
keyExtractor={(item: TPopoverMenuOptions) => item.key}
|
||||
panelClassName="p-0 py-2 rounded-md border border-custom-border-200 bg-custom-background-100 space-y-1"
|
||||
render={(item: TPopoverMenuOptions) => <NotificationMenuOptionItem {...item} />}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
|
@ -66,12 +66,9 @@ export const NotificationsSidebar: FC = observer(() => {
|
|||
)}
|
||||
>
|
||||
<div className="font-medium">{tab.label}</div>
|
||||
<CountChip
|
||||
count={getNumberCount(tab.count(unreadNotificationsCount))}
|
||||
className={
|
||||
currentNotificationTab === tab.value ? `bg-custom-primary-100/20` : `bg-custom-background-80/50`
|
||||
}
|
||||
/>
|
||||
{tab.count(unreadNotificationsCount) > 0 && (
|
||||
<CountChip count={getNumberCount(tab.count(unreadNotificationsCount))} />
|
||||
)}
|
||||
</div>
|
||||
{currentNotificationTab === tab.value && (
|
||||
<div className="border absolute bottom-0 right-0 left-0 rounded-t-md border-custom-primary-100" />
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ export enum EmptyStateType {
|
|||
ISSUE_RELATION_EMPTY_STATE = "issue-relation-empty-state",
|
||||
ISSUE_COMMENT_EMPTY_STATE = "issue-comment-empty-state",
|
||||
|
||||
NOTIFICATION_DETAIL_EMPTY_STATE = "notification-detail-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",
|
||||
|
|
@ -595,6 +596,11 @@ const emptyStateDetails = {
|
|||
path: "/empty-state/search/comments",
|
||||
},
|
||||
|
||||
[EmptyStateType.NOTIFICATION_DETAIL_EMPTY_STATE]: {
|
||||
key: EmptyStateType.INBOX_DETAIL_EMPTY_STATE,
|
||||
title: "Select to view details.",
|
||||
path: "/empty-state/inbox/issue-detail",
|
||||
},
|
||||
[EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE]: {
|
||||
key: EmptyStateType.NOTIFICATION_ALL_EMPTY_STATE,
|
||||
title: "No issues assigned",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue