From c12790f091b184c4f29888772daf1460b2b6379a Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:55:58 +0530 Subject: [PATCH] feat(notifications): integrate Drawer for mobile notifications and enhance UI components - Added Drawer component to NotificationsDropdown for improved mobile experience. - Refactored notification trigger button and panel content for better accessibility and usability. - Enhanced loading states and notification filtering options to streamline user interaction. --- .../ui/sidebar/NotificationsDropdown.tsx | 341 ++++++++++-------- 1 file changed, 186 insertions(+), 155 deletions(-) diff --git a/surfsense_web/components/layout/ui/sidebar/NotificationsDropdown.tsx b/surfsense_web/components/layout/ui/sidebar/NotificationsDropdown.tsx index 3ada5de46..bf3ce4322 100644 --- a/surfsense_web/components/layout/ui/sidebar/NotificationsDropdown.tsx +++ b/surfsense_web/components/layout/ui/sidebar/NotificationsDropdown.tsx @@ -6,6 +6,13 @@ import { useRouter } from "next/navigation"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { setTargetCommentIdAtom } from "@/atoms/chat/current-thread.atom"; import { Button } from "@/components/ui/button"; +import { + Drawer, + DrawerContent, + DrawerHandle, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Skeleton } from "@/components/ui/skeleton"; import { Spinner } from "@/components/ui/spinner"; @@ -16,6 +23,7 @@ import { isNewMentionMetadata, } from "@/contracts/types/inbox.types"; import type { InboxItem } from "@/hooks/use-inbox"; +import { useIsMobile } from "@/hooks/use-mobile"; import { cn } from "@/lib/utils"; export interface NotificationsDataSource { @@ -79,6 +87,7 @@ export function NotificationsDropdown({ onCloseMobileSidebar, }: NotificationsDropdownProps) { const router = useRouter(); + const isMobile = useIsMobile(); const [, setTargetCommentId] = useAtom(setTargetCommentIdAtom); const [open, setOpen] = useState(false); const [activeFilter, setActiveFilter] = useState("all"); @@ -260,33 +269,186 @@ export function NotificationsDropdown({ { value: "unread", label: "Unread", count: notifications.totalUnreadCount }, ]; + const triggerButton = ( + + ); + + const panelContent = ( + <> +
+
+

Notifications

+
+ +
+ +
+ {tabs.map((tab) => { + const isActive = activeFilter === tab.value; + return ( + + ); + })} +
+ +
+ {isLoading ? ( +
+ {[82, 64, 74].map((width) => ( +
+
+ + +
+
+ ))} +
+ ) : items.length > 0 ? ( +
+ {items.map((item) => { + const isMarkingAsRead = markingAsReadId === item.id; + return ( + + ); + })} + {hasMore ? ( +
+ {isLoadingMore ? : null} +
+ ) : null} +
+ ) : ( +
+

{emptyStateCopy.title}

+

{emptyStateCopy.description}

+ {hasMore ? ( + + ) : null} +
+ )} +
+ + ); + + if (isMobile) { + return ( + + {triggerButton} + + + Notifications +
{panelContent}
+
+
+ ); + } + return ( - - - + {triggerButton} Notifications @@ -298,138 +460,7 @@ export function NotificationsDropdown({ sideOffset={10} className="z-80 flex max-h-[min(520px,calc(100vh-2rem))] w-[360px] flex-col overflow-hidden rounded-xl border bg-popover p-0 text-popover-foreground shadow-lg" > -
-
-

Notifications

-
- -
- -
- {tabs.map((tab) => { - const isActive = activeFilter === tab.value; - return ( - - ); - })} -
- -
- {isLoading ? ( -
- {[82, 64, 74].map((width) => ( -
-
- - -
-
- ))} -
- ) : items.length > 0 ? ( -
- {items.map((item) => { - const isMarkingAsRead = markingAsReadId === item.id; - return ( - - ); - })} - {hasMore ? ( -
- {isLoadingMore ? : null} -
- ) : null} -
- ) : ( -
-

{emptyStateCopy.title}

-

{emptyStateCopy.description}

- {hasMore ? ( - - ) : null} -
- )} -
+ {panelContent}
);