LayoutSidebarProvider.tsx133 lines · main
1// @ts-nocheck
2import { LOCAL_STORAGE_KEYS } from 'common'
3import dynamic from 'next/dynamic'
4import { useRouter } from 'next/router'
5import { parseAsString, useQueryState } from 'nuqs'
6import { useEffect, type PropsWithChildren } from 'react'
7
8import { getSupportLinkQueryParams } from '@/components/ui/HelpPanel/HelpPanel.utils'
9import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
10import useLatest from '@/hooks/misc/useLatest'
11import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
12import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
13import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
14import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
15import { useShortcut } from '@/state/shortcuts/useShortcut'
16import {
17 sidebarManagerState,
18 useRegisterSidebar,
19 useSidebarManagerSnapshot,
20} from '@/state/sidebar-manager-state'
21
22const AdvisorPanel = dynamic(() =>
23 import('@/components/ui/AdvisorPanel/AdvisorPanel').then((m) => m.AdvisorPanel)
24)
25const AIAssistant = dynamic(() =>
26 import('@/components/ui/AIAssistantPanel/AIAssistant').then((m) => m.AIAssistant)
27)
28const EditorPanel = dynamic(() =>
29 import('@/components/ui/EditorPanel/EditorPanel').then((m) => m.EditorPanel)
30)
31const HelpPanel = dynamic(() =>
32 import('@/components/ui/HelpPanel/HelpPanel').then((m) => m.HelpPanel)
33)
34
35export const SIDEBAR_KEYS = {
36 AI_ASSISTANT: 'ai-assistant',
37 EDITOR_PANEL: 'editor-panel',
38 ADVISOR_PANEL: 'advisor-panel',
39 HELP_PANEL: 'help-panel',
40} as const
41
42export type TYPEOF_SIDEBAR_KEYS = (typeof SIDEBAR_KEYS)[keyof typeof SIDEBAR_KEYS]
43
44export const LayoutSidebarProvider = ({ children }: PropsWithChildren) => {
45 const router = useRouter()
46 const { data: project } = useSelectedProjectQuery()
47 const { data: org } = useSelectedOrganizationQuery()
48 const { mutate: sendEvent } = useSendEventMutation()
49 const { openSidebar, closeSidebar, activeSidebar } = useSidebarManagerSnapshot()
50
51 const [sidebarURLParam, setSidebarUrlParam] = useQueryState('sidebar', parseAsString)
52 const [sidebarLocalStorage, setSidebarLocalStorage, { isSuccess: isLoadedLocalStorage }] =
53 useLocalStorageQuery(LOCAL_STORAGE_KEYS.LAST_OPENED_SIDE_BAR(project?.ref ?? ''), '')
54
55 const sidebarURLParamRef = useLatest(sidebarURLParam)
56 const sidebarLocalStorageRef = useLatest(sidebarLocalStorage)
57
58 useRegisterSidebar(SIDEBAR_KEYS.AI_ASSISTANT, () => <AIAssistant />, {}, !!project)
59 useRegisterSidebar(SIDEBAR_KEYS.EDITOR_PANEL, () => <EditorPanel />, {}, !!project)
60 useRegisterSidebar(SIDEBAR_KEYS.ADVISOR_PANEL, () => <AdvisorPanel />, {}, true)
61 useRegisterSidebar(
62 SIDEBAR_KEYS.HELP_PANEL,
63 () => (
64 <HelpPanel
65 onClose={() => closeSidebar(SIDEBAR_KEYS.HELP_PANEL)}
66 projectRef={project?.ref}
67 supportLinkQueryParams={getSupportLinkQueryParams(
68 project,
69 org,
70 router.query.ref as string | undefined
71 )}
72 />
73 ),
74 {},
75 true
76 )
77
78 useShortcut(SHORTCUT_IDS.AI_ASSISTANT_TOGGLE, () =>
79 sidebarManagerState.toggleSidebar(SIDEBAR_KEYS.AI_ASSISTANT)
80 )
81 useShortcut(SHORTCUT_IDS.INLINE_EDITOR_TOGGLE, () =>
82 sidebarManagerState.toggleSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
83 )
84
85 useEffect(() => {
86 if (!!project) {
87 if (activeSidebar) {
88 // add event tracking
89 sendEvent({
90 action: 'sidebar_opened',
91 properties: {
92 sidebar: activeSidebar.id as (typeof SIDEBAR_KEYS)[keyof typeof SIDEBAR_KEYS],
93 },
94 groups: {
95 project: project?.ref ?? 'Unknown',
96 organization: org?.slug ?? 'Unknown',
97 },
98 })
99 setSidebarLocalStorage(activeSidebar.id)
100 } else {
101 setSidebarLocalStorage('')
102 setSidebarUrlParam(null)
103 }
104 }
105 // eslint-disable-next-line react-hooks/exhaustive-deps
106 }, [activeSidebar])
107
108 // Handle toggling of sidebars on page init
109 // Prioritize URL params first, then local storage
110 useEffect(() => {
111 if (router.isReady && isLoadedLocalStorage) {
112 if (
113 typeof sidebarURLParamRef.current === 'string' &&
114 Object.values(SIDEBAR_KEYS).includes(
115 sidebarURLParamRef.current as (typeof SIDEBAR_KEYS)[keyof typeof SIDEBAR_KEYS]
116 )
117 ) {
118 console.log('Open sidebar based on URL')
119 openSidebar(sidebarURLParamRef.current)
120 } else if (
121 !!sidebarLocalStorageRef.current &&
122 Object.values(SIDEBAR_KEYS).includes(
123 sidebarLocalStorageRef.current as (typeof SIDEBAR_KEYS)[keyof typeof SIDEBAR_KEYS]
124 )
125 ) {
126 openSidebar(sidebarLocalStorageRef.current)
127 }
128 }
129 // eslint-disable-next-line react-hooks/exhaustive-deps
130 }, [router.isReady, isLoadedLocalStorage])
131
132 return <>{children}</>
133}