diff --git a/packages/ui/src/features/canvas/components/ChannelNav.test.tsx b/packages/ui/src/features/canvas/components/ChannelNav.test.tsx index fe2da703cb..c0a07f9162 100644 --- a/packages/ui/src/features/canvas/components/ChannelNav.test.tsx +++ b/packages/ui/src/features/canvas/components/ChannelNav.test.tsx @@ -74,9 +74,48 @@ describe("ChannelNav", () => { const activity = screen.getByLabelText("Activity"); expect(activity).toBeEnabled(); + expect(activity).not.toHaveAttribute("aria-haspopup"); await user.hover(activity); await new Promise((resolve) => setTimeout(resolve, 400)); expect(screen.queryByText("Recent activity card")).not.toBeInTheDocument(); }); + + it("leaves no popover state on the bell after it navigates to Activity", async () => { + const user = userEvent.setup(); + const { rerender } = render(); + const bell = () => screen.getByLabelText("Activity"); + + await user.hover(bell()); + await screen.findByText("Recent activity card", {}, { timeout: 1_000 }); + await user.click(bell()); + mocks.view = { type: "activity" }; + rerender(); + + expect(screen.queryByText("Recent activity card")).not.toBeInTheDocument(); + expect(bell()).not.toHaveAttribute("data-popup-open"); + expect(bell()).not.toHaveAttribute("data-pressed"); + }); + + it("neither resurfaces nor wedges the hover card once the bell has navigated", async () => { + const user = userEvent.setup(); + const { rerender } = render(); + const bell = () => screen.getByLabelText("Activity"); + + await user.hover(bell()); + await user.click(bell()); + mocks.view = { type: "activity" }; + rerender(); + await user.unhover(bell()); + + mocks.view = { type: "task-detail" }; + rerender(); + await new Promise((resolve) => setTimeout(resolve, 400)); + expect(screen.queryByText("Recent activity card")).not.toBeInTheDocument(); + + await user.hover(bell()); + expect( + await screen.findByText("Recent activity card", {}, { timeout: 1_000 }), + ).toBeInTheDocument(); + }); }); diff --git a/packages/ui/src/features/canvas/components/ChannelNav.tsx b/packages/ui/src/features/canvas/components/ChannelNav.tsx index fe76afeb19..a92e23a96b 100644 --- a/packages/ui/src/features/canvas/components/ChannelNav.tsx +++ b/packages/ui/src/features/canvas/components/ChannelNav.tsx @@ -39,7 +39,12 @@ import { } from "@posthog/ui/router/navigationBridge"; import { useAppView } from "@posthog/ui/router/useAppView"; import { track } from "@posthog/ui/shell/analytics"; -import { type ComponentPropsWithRef, type ReactNode, useState } from "react"; +import { + type ComponentPropsWithRef, + type ReactElement, + type ReactNode, + useState, +} from "react"; import { ActivityHoverCard } from "./ActivityHoverCard"; const INBOX_REFETCH_INTERVAL_MS = 60_000; @@ -133,10 +138,51 @@ function NavButton({ ); } +function ActivityHoverPopover({ trigger }: { trigger: ReactElement }) { + const [open, setOpen] = useState(false); + + return ( + + event.preventBaseUIHandler()} + render={trigger} + /> + {open && ( + setOpen(false)} /> + )} + + ); +} + +function ActivityNavItem({ + isActive, + unreadCount, + onNavigate, +}: { + isActive: boolean; + unreadCount: number; + onNavigate: () => void; +}) { + const bell = ( + } + label="Activity" + isActive={isActive} + onClick={onNavigate} + badge={} + /> + ); + + if (isActive) return bell; + return ; +} + export function ChannelNav() { const view = useAppView(); const loopsEnabled = useFeatureFlag(LOOPS_FLAG, import.meta.env.DEV); - const [activityOpen, setActivityOpen] = useState(false); const { counts } = useInboxAllReports({ ignoreFilters: true, @@ -178,44 +224,11 @@ export function ChannelNav() { } /> - setActivityOpen(!isActivity && open)} - > - - } - label="Activity" - isActive={isActivity} - onClick={() => { - setActivityOpen(false); - withTrack("activity", navigateToActivity)(); - }} - badge={ - - } - /> - } - /> - {!isActivity && activityOpen && ( - setActivityOpen(false)} - /> - )} - +