LayoutSidebarProvider.tsx 4.7 KB

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