From d36d48df766cba229903497efa97727d4b81efa6 Mon Sep 17 00:00:00 2001 From: Stevche Radevski Date: Thu, 1 Aug 2024 17:10:34 +0200 Subject: [PATCH] feat: Show notice on new notifications (#8390) --- .../layout/notifications/notifications.tsx | 96 +++++++++++++++---- .../src/http/notification/admin/entities.ts | 2 +- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/packages/admin-next/dashboard/src/components/layout/notifications/notifications.tsx b/packages/admin-next/dashboard/src/components/layout/notifications/notifications.tsx index df1b29c219..6786f5f774 100644 --- a/packages/admin-next/dashboard/src/components/layout/notifications/notifications.tsx +++ b/packages/admin-next/dashboard/src/components/layout/notifications/notifications.tsx @@ -1,6 +1,7 @@ import { BellAlert, BellAlertDone, + CircleFilledSolid, InformationCircleSolid, } from "@medusajs/icons" import { Drawer, Heading, IconButton, Text } from "@medusajs/ui" @@ -10,7 +11,7 @@ import { HttpTypes } from "@medusajs/types" import { formatDistance } from "date-fns" import { InfiniteList } from "../../common/infinite-list" import { sdk } from "../../../lib/client" -import { notificationQueryKeys } from "../../../hooks/api" +import { notificationQueryKeys, useNotifications } from "../../../hooks/api" import { TFunction } from "i18next" import { FilePreview } from "../../common/file-preview" @@ -24,9 +25,17 @@ interface NotificationData { } } +const LAST_READ_NOTIFICATION_KEY = "notificationsLastReadAt" + export const Notifications = () => { - const [open, setOpen] = useState(false) const { t } = useTranslation() + const [open, setOpen] = useState(false) + const [hasUnread, setHasUnread] = useUnreadNotifications() + // This is used to show the unread icon on the notification when the drawer is open, + // so it should lag behind the local storage data and should only be reset on close + const [lastReadAt, setLastReadAt] = useState( + localStorage.getItem(LAST_READ_NOTIFICATION_KEY) + ) useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { @@ -42,14 +51,25 @@ export const Notifications = () => { } }, []) + const handleOnOpen = (isOpen: boolean) => { + if (isOpen) { + setHasUnread(false) + setOpen(true) + localStorage.setItem(LAST_READ_NOTIFICATION_KEY, new Date().toISOString()) + } else { + setOpen(false) + setLastReadAt(localStorage.getItem(LAST_READ_NOTIFICATION_KEY)) + } + } + return ( - + - + {hasUnread ? : } @@ -77,6 +97,10 @@ export const Notifications = () => { + (lastReadAt ? Date.parse(lastReadAt) : 0) + } /> ) }} @@ -89,8 +113,10 @@ export const Notifications = () => { const Notification = ({ notification, + unread, }: { notification: HttpTypes.AdminNotification + unread?: boolean }) => { const data = notification.data as unknown as NotificationData | undefined @@ -101,27 +127,35 @@ const Notification = ({ return ( <> -
+
-
+
{data.title} - - {formatDistance(notification.created_at, new Date(), { - addSuffix: true, - })} - +
+ + {formatDistance(notification.created_at, new Date(), { + addSuffix: true, + })} + + {unread && ( + + )} +
{!!data.description && ( {
) } + +const useUnreadNotifications = () => { + const [hasUnread, setHasUnread] = useState(false) + const { notifications } = useNotifications( + { limit: 1, offset: 0, fields: "created_at" }, + { refetchInterval: 3000 } + ) + const lastNotification = notifications?.[0] + + useEffect(() => { + if (!lastNotification) { + return + } + + const lastNotificationAsTimestamp = Date.parse(lastNotification.created_at) + + const lastReadDatetime = localStorage.getItem(LAST_READ_NOTIFICATION_KEY) + const lastReadAsTimestamp = lastReadDatetime + ? Date.parse(lastReadDatetime) + : 0 + + if (lastNotificationAsTimestamp > lastReadAsTimestamp) { + setHasUnread(true) + } + }, [lastNotification]) + + return [hasUnread, setHasUnread] as const +} diff --git a/packages/core/types/src/http/notification/admin/entities.ts b/packages/core/types/src/http/notification/admin/entities.ts index dddfc21e20..f425be154b 100644 --- a/packages/core/types/src/http/notification/admin/entities.ts +++ b/packages/core/types/src/http/notification/admin/entities.ts @@ -11,5 +11,5 @@ export interface AdminNotification { original_notification_id?: string | null external_id?: string | null provider_id: string - created_at: Date + created_at: string }