From 298ad6227b932e7cdf5589c17c2865b15440d931 Mon Sep 17 00:00:00 2001 From: Nathnael Date: Mon, 6 Jul 2026 10:54:43 +0000 Subject: [PATCH] style: ui improvement to the notification cards. --- .../notification-inbox.controller.ts | 14 ++- .../notification-inbox.service.ts | 12 ++- .../NotificationBellContainer.tsx | 1 + .../notifications/notificationConfig.tsx | 2 +- .../NotificationBellContainer.tsx | 1 + .../notifications/notificationConfig.tsx | 2 +- .../NotificationBell/NotificationDrawer.tsx | 98 +++++++++++-------- .../NotificationBell/NotificationItem.tsx | 84 ++++++++++------ .../NotificationBell/NotificationToast.tsx | 63 ++++++------ .../NotificationBell/PriorityTag.tsx | 41 ++++++++ .../src/components/NotificationBell/types.ts | 2 + 11 files changed, 211 insertions(+), 109 deletions(-) create mode 100644 packages/ui-common/src/components/NotificationBell/PriorityTag.tsx diff --git a/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts b/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts index 968dd8adb..1d7fd27fc 100644 --- a/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts +++ b/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.controller.ts @@ -1,5 +1,9 @@ import { CurrentUser } from "@edr/api-common"; -import { NotificationAudience } from "@edr/types"; +import { + NotificationAudience, + NotificationPriority, + NotificationType, +} from "@edr/types"; import { Body, Controller, @@ -62,7 +66,13 @@ export class NotificationInboxController { sendTest( @CurrentUser() user: AuthUserPayload, @Body() - body: { audience?: NotificationAudience; title?: string; message?: string }, + body: { + audience?: NotificationAudience; + type?: NotificationType; + priority?: NotificationPriority; + title?: string; + message?: string; + }, ) { return this.service.sendTestToUser(resolveAuthUserId(user), body ?? {}); } diff --git a/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.service.ts b/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.service.ts index 0c899fc29..97ee0380e 100644 --- a/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.service.ts +++ b/apps/edr-freight-api/src/modules/notification-inbox/notification-inbox.service.ts @@ -109,15 +109,21 @@ export class NotificationInboxService { /** [dev/verification only] Send a canned notification straight to one user. */ async sendTestToUser( userId: string, - body: { audience?: NotificationAudience; title?: string; message?: string }, + body: { + audience?: NotificationAudience; + type?: NotificationType; + priority?: NotificationPriority; + title?: string; + message?: string; + }, ): Promise { const entity = await this.repo.create({ recipientUserId: userId, audience: body.audience ?? NotificationAudience.BACKOFFICE, - type: NotificationType.GENERIC, + type: body.type ?? NotificationType.GENERIC, title: body.title ?? "Test notification", body: body.message ?? "This is a test in-app notification.", - priority: NotificationPriority.NORMAL, + priority: body.priority ?? NotificationPriority.NORMAL, isRead: false, }); const dto = this.toDto(entity); diff --git a/apps/edr-freight-web/backoffice/src/features/notifications/NotificationBellContainer.tsx b/apps/edr-freight-web/backoffice/src/features/notifications/NotificationBellContainer.tsx index 8c8ed749f..aed40d951 100644 --- a/apps/edr-freight-web/backoffice/src/features/notifications/NotificationBellContainer.tsx +++ b/apps/edr-freight-web/backoffice/src/features/notifications/NotificationBellContainer.tsx @@ -30,6 +30,7 @@ function toItem(n: NotificationDto): NotificationItemData { body: n.body, createdAt: n.createdAt, isRead: n.isRead, + priority: n.priority, link: n.link, data: n.data, }; diff --git a/apps/edr-freight-web/backoffice/src/features/notifications/notificationConfig.tsx b/apps/edr-freight-web/backoffice/src/features/notifications/notificationConfig.tsx index 8d18f9347..9baf4ebf2 100644 --- a/apps/edr-freight-web/backoffice/src/features/notifications/notificationConfig.tsx +++ b/apps/edr-freight-web/backoffice/src/features/notifications/notificationConfig.tsx @@ -20,7 +20,7 @@ export function resolveNotificationVisual( case NotificationType.CLEARANCE_REVIEW: return { icon: , color: "orange" }; default: - return { icon: , color: "gray" }; + return { icon: , color: "edr-green" }; } } diff --git a/apps/edr-freight-web/portal/src/features/notifications/NotificationBellContainer.tsx b/apps/edr-freight-web/portal/src/features/notifications/NotificationBellContainer.tsx index 8c8ed749f..aed40d951 100644 --- a/apps/edr-freight-web/portal/src/features/notifications/NotificationBellContainer.tsx +++ b/apps/edr-freight-web/portal/src/features/notifications/NotificationBellContainer.tsx @@ -30,6 +30,7 @@ function toItem(n: NotificationDto): NotificationItemData { body: n.body, createdAt: n.createdAt, isRead: n.isRead, + priority: n.priority, link: n.link, data: n.data, }; diff --git a/apps/edr-freight-web/portal/src/features/notifications/notificationConfig.tsx b/apps/edr-freight-web/portal/src/features/notifications/notificationConfig.tsx index 89bf880fe..42f3294f7 100644 --- a/apps/edr-freight-web/portal/src/features/notifications/notificationConfig.tsx +++ b/apps/edr-freight-web/portal/src/features/notifications/notificationConfig.tsx @@ -28,7 +28,7 @@ export function resolveNotificationVisual( case NotificationType.INVOICE_ISSUED: return { icon: , color: "violet" }; default: - return { icon: , color: "gray" }; + return { icon: , color: "edr-green" }; } } diff --git a/packages/ui-common/src/components/NotificationBell/NotificationDrawer.tsx b/packages/ui-common/src/components/NotificationBell/NotificationDrawer.tsx index 460848e25..3be7c801b 100644 --- a/packages/ui-common/src/components/NotificationBell/NotificationDrawer.tsx +++ b/packages/ui-common/src/components/NotificationBell/NotificationDrawer.tsx @@ -9,11 +9,13 @@ import { ScrollArea, Stack, Text, + ThemeIcon, } from "@mantine/core"; -import { CheckCheck, Inbox, X } from "lucide-react"; +import { Bell, CheckCheck, Inbox, X } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { NotificationItem } from "./NotificationItem"; +import { edr } from "./PriorityTag"; import type { NotificationItemData, ResolveNotificationVisual, @@ -73,36 +75,39 @@ function Sentinel({ } function SectionLabel({ - children, - right, + label, + count, }: { - children: React.ReactNode; - right?: React.ReactNode; + label: string; + count?: number; }) { return ( - {children} + {label} - {right} + {typeof count === "number" && count > 0 && ( + + {count} + + )} ); } @@ -110,15 +115,16 @@ function SectionLabel({ function LoadingRow() { return ( - + ); } /** - * Right slide-in notification center: an "Unread" section over an "Earlier" - * (read) section, each with its own infinite-scroll trigger, in one scroll - * surface. Presentational — the host wires data, paging, and the visual registry. + * Right slide-in notification center, styled to the EDR design system: a + * branded header, an "Unread" section over an "Earlier" (read) section, each + * with its own infinite-scroll trigger in one scroll surface. Presentational — + * the host wires data, paging, and the visual registry. */ export function NotificationDrawer({ opened, @@ -138,7 +144,7 @@ export function NotificationDrawer({ resolveVisual, emptyLabel = "You're all caught up", title = "Notifications", - width = 420, + width = 424, }: NotificationDrawerProps) { const [viewport, setViewport] = useState(null); const viewportRef = useRef(null); @@ -168,10 +174,14 @@ export function NotificationDrawer({ size={width} padding={0} withCloseButton={false} - overlayProps={{ backgroundOpacity: 0.35, blur: 2 }} - transitionProps={{ transition: "slide-left" }} + overlayProps={{ backgroundOpacity: 0.45, blur: 3 }} + transitionProps={{ transition: "slide-left", duration: 220 }} styles={{ - content: { display: "flex", flexDirection: "column" }, + content: { + display: "flex", + flexDirection: "column", + background: edr.card, + }, body: { flex: 1, minHeight: 0, @@ -184,18 +194,24 @@ export function NotificationDrawer({ - - - {title} - + + + + + + + {title} + + + {totalUnread > 0 ? `${totalUnread} unread` : "All caught up"} + + {totalUnread > 0 && ( - + {totalUnread > 99 ? "99+" : totalUnread} )} @@ -205,7 +221,7 @@ export function NotificationDrawer({