From 9eb5a60fb2ee8bf9658b2734d01b00daf544321a Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:56:16 +0100 Subject: [PATCH] feat: add unread messages badge and live updates in sidebar - Display unread message count badge in the sidebar. - Integrate `useSocket` for real-time updates on unread messages. - Reset unread message count when navigating to the messages page. - Increment badge count on receiving `new_message` WebSocket events. --- frontend/src/components/app-sidebar.tsx | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/frontend/src/components/app-sidebar.tsx b/frontend/src/components/app-sidebar.tsx index 8b8e104..7cb10f1 100644 --- a/frontend/src/components/app-sidebar.tsx +++ b/frontend/src/components/app-sidebar.tsx @@ -45,6 +45,7 @@ import { SidebarGroupLabel, SidebarHeader, SidebarMenu, + SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, @@ -54,7 +55,9 @@ import { SidebarTrigger, } from "@/components/ui/sidebar"; import { useAuth } from "@/providers/auth-provider"; +import { useSocket } from "@/providers/socket-provider"; import { CategoryService } from "@/services/category.service"; +import { MessageService } from "@/services/message.service"; import type { Category } from "@/types/content"; const mainNav = [ @@ -79,15 +82,46 @@ export function AppSidebar() { const pathname = usePathname(); const searchParams = useSearchParams(); const { user, logout, isAuthenticated } = useAuth(); + const { socket } = useSocket(); const { resolvedTheme } = useTheme(); const [categories, setCategories] = React.useState([]); const [mounted, setMounted] = React.useState(false); + const [unreadMessages, setUnreadMessages] = React.useState(0); React.useEffect(() => { setMounted(true); CategoryService.getAll().then(setCategories).catch(console.error); }, []); + // Gérer le compteur de messages non-lus + React.useEffect(() => { + if (isAuthenticated) { + MessageService.getUnreadCount().then(setUnreadMessages).catch(console.error); + } + }, [isAuthenticated]); + + React.useEffect(() => { + if (socket && isAuthenticated) { + socket.on("new_message", () => { + // Incrémenter si on n'est pas sur la page messages + if (pathname !== "/messages") { + setUnreadMessages((prev) => prev + 1); + } + }); + + return () => { + socket.off("new_message"); + }; + } + }, [socket, isAuthenticated, pathname]); + + // Remettre à zéro si on arrive sur la page messages + React.useEffect(() => { + if (pathname === "/messages") { + setUnreadMessages(0); + } + }, [pathname]); + const logoSrc = React.useMemo(() => { if (!mounted) return "/memegoat-color.svg"; return resolvedTheme === "dark" @@ -193,6 +227,11 @@ export function AppSidebar() { Messages + {unreadMessages > 0 && ( + + {unreadMessages > 9 ? "9+" : unreadMessages} + + )} )}