AdvisorButton.tsx82 lines · main
1import { Lightbulb } from 'lucide-react'
2import { useMemo } from 'react'
3import { cn } from 'ui'
4
5import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
6import { useAdvisorSignals } from '@/components/ui/AdvisorPanel/useAdvisorSignals'
7import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
8import { useProjectLintsQuery } from '@/data/lint/lint-query'
9import { useNotificationsV2Query } from '@/data/notifications/notifications-v2-query'
10import { useTrack } from '@/lib/telemetry/track'
11import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
12
13export const AdvisorButton = ({ projectRef }: { projectRef?: string }) => {
14 const { toggleSidebar, activeSidebar } = useSidebarManagerSnapshot()
15 const track = useTrack()
16
17 const { data: lints } = useProjectLintsQuery({ projectRef })
18 const { data: signalItems } = useAdvisorSignals({ projectRef })
19
20 const { data: notificationsData } = useNotificationsV2Query({
21 filters: {},
22 limit: 20,
23 })
24 const notifications = useMemo(() => {
25 return notificationsData?.pages.flatMap((page) => page) ?? []
26 }, [notificationsData?.pages])
27 const hasUnreadNotifications = notifications.some((x) => x?.status === 'new')
28 const hasCriticalNotifications = notifications.some((x) => x?.priority === 'Critical')
29 const hasSignals = signalItems.length > 0
30 const hasCriticalSignals = signalItems.some((item) => item.severity === 'critical')
31
32 const hasCriticalIssues =
33 hasCriticalNotifications ||
34 hasCriticalSignals ||
35 (Array.isArray(lints) && lints.some((lint) => lint.level === 'ERROR'))
36 const hasWarningIssues = hasSignals && !hasCriticalIssues
37
38 const isOpen = activeSidebar?.id === SIDEBAR_KEYS.ADVISOR_PANEL
39
40 const handleClick = () => {
41 track('header_advisor_button_clicked')
42 toggleSidebar(SIDEBAR_KEYS.ADVISOR_PANEL)
43 }
44
45 return (
46 <div className="relative">
47 <ButtonTooltip
48 type="outline"
49 size="tiny"
50 id="advisor-center-trigger"
51 className={cn(
52 'rounded-full w-[32px] h-[32px] flex items-center justify-center p-0 group',
53 hasCriticalIssues && 'bg-destructive-200 border-destructive-500',
54 isOpen && 'bg-foreground text-background'
55 )}
56 onClick={handleClick}
57 tooltip={{
58 content: {
59 text: 'Advisor Center',
60 },
61 }}
62 >
63 <Lightbulb
64 size={16}
65 strokeWidth={1.5}
66 className={cn(
67 'text-foreground-light group-hover:text-foreground',
68 isOpen && 'text-background group-hover:text-background'
69 )}
70 />
71 <span className="sr-only">Advisor Center</span>
72 </ButtonTooltip>
73 {hasCriticalIssues ? (
74 <span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-destructive" />
75 ) : hasWarningIssues ? (
76 <span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-warning" />
77 ) : hasUnreadNotifications ? (
78 <span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-brand" />
79 ) : null}
80 </div>
81 )
82}