LayoutSidebarProvider.tsx133 lines · main
| 1 | // @ts-nocheck |
| 2 | import { LOCAL_STORAGE_KEYS } from 'common' |
| 3 | import dynamic from 'next/dynamic' |
| 4 | import { useRouter } from 'next/router' |
| 5 | import { parseAsString, useQueryState } from 'nuqs' |
| 6 | import { useEffect, type PropsWithChildren } from 'react' |
| 7 | |
| 8 | import { getSupportLinkQueryParams } from '@/components/ui/HelpPanel/HelpPanel.utils' |
| 9 | import { useSendEventMutation } from '@/data/telemetry/send-event-mutation' |
| 10 | import useLatest from '@/hooks/misc/useLatest' |
| 11 | import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' |
| 12 | import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' |
| 13 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 14 | import { SHORTCUT_IDS } from '@/state/shortcuts/registry' |
| 15 | import { useShortcut } from '@/state/shortcuts/useShortcut' |
| 16 | import { |
| 17 | sidebarManagerState, |
| 18 | useRegisterSidebar, |
| 19 | useSidebarManagerSnapshot, |
| 20 | } from '@/state/sidebar-manager-state' |
| 21 | |
| 22 | const AdvisorPanel = dynamic(() => |
| 23 | import('@/components/ui/AdvisorPanel/AdvisorPanel').then((m) => m.AdvisorPanel) |
| 24 | ) |
| 25 | const AIAssistant = dynamic(() => |
| 26 | import('@/components/ui/AIAssistantPanel/AIAssistant').then((m) => m.AIAssistant) |
| 27 | ) |
| 28 | const EditorPanel = dynamic(() => |
| 29 | import('@/components/ui/EditorPanel/EditorPanel').then((m) => m.EditorPanel) |
| 30 | ) |
| 31 | const HelpPanel = dynamic(() => |
| 32 | import('@/components/ui/HelpPanel/HelpPanel').then((m) => m.HelpPanel) |
| 33 | ) |
| 34 | |
| 35 | export 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 | |
| 42 | export type TYPEOF_SIDEBAR_KEYS = (typeof SIDEBAR_KEYS)[keyof typeof SIDEBAR_KEYS] |
| 43 | |
| 44 | export 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 | } |