AccountLayout.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { LOCAL_STORAGE_KEYS } from 'common'
  2. import Head from 'next/head'
  3. import { useRouter } from 'next/router'
  4. import type { PropsWithChildren } from 'react'
  5. import { useEffect, useLayoutEffect, useMemo } from 'react'
  6. import { cn } from 'ui'
  7. import { useMobileSheet } from '../Navigation/NavigationBar/MobileSheetContext'
  8. import { AccountMenuContent } from './AccountMenuContent'
  9. import { WithSidebar } from './WithSidebar'
  10. import { useCustomContent } from '@/hooks/custom-content/useCustomContent'
  11. import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
  12. import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
  13. import { withAuth } from '@/hooks/misc/withAuth'
  14. import { IS_PLATFORM } from '@/lib/constants'
  15. import { buildStudioPageTitle } from '@/lib/page-title'
  16. import { useAppStateSnapshot } from '@/state/app-state'
  17. export interface AccountLayoutProps {
  18. title: string
  19. }
  20. const AccountLayout = ({ children, title }: PropsWithChildren<AccountLayoutProps>) => {
  21. const router = useRouter()
  22. const appSnap = useAppStateSnapshot()
  23. const { setContent: setMobileSheetContent, registerOpenMenu } = useMobileSheet()
  24. const currentPath = router.pathname
  25. const showSecuritySettings = useIsFeatureEnabled('account:show_security_settings')
  26. const { appTitle } = useCustomContent(['app:title'])
  27. const brandTitle = appTitle || 'Briven'
  28. const surfaceLabel = IS_PLATFORM ? 'Account' : 'Preferences'
  29. const [lastVisitedOrganization] = useLocalStorageQuery(
  30. LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION,
  31. ''
  32. )
  33. const backToDashboardURL =
  34. appSnap.lastRouteBeforeVisitingAccountPage.length > 0
  35. ? appSnap.lastRouteBeforeVisitingAccountPage
  36. : IS_PLATFORM && !!lastVisitedOrganization
  37. ? `/org/${lastVisitedOrganization}`
  38. : IS_PLATFORM
  39. ? '/organizations'
  40. : '/project/default'
  41. const pageTitle = buildStudioPageTitle({
  42. section: title,
  43. surface: surfaceLabel,
  44. brand: brandTitle,
  45. })
  46. const sections = useMemo(
  47. () =>
  48. !IS_PLATFORM
  49. ? [
  50. {
  51. key: 'preferences',
  52. links: [
  53. {
  54. key: 'preferences',
  55. label: 'Preferences',
  56. href: '/account/me',
  57. isActive: currentPath === '/account/me',
  58. },
  59. ],
  60. },
  61. ]
  62. : [
  63. {
  64. key: 'account-settings',
  65. heading: 'Account Settings',
  66. links: [
  67. {
  68. key: 'preferences',
  69. label: 'Preferences',
  70. href: '/account/me',
  71. isActive: currentPath === '/account/me',
  72. },
  73. {
  74. key: 'access-tokens',
  75. label: 'Access Tokens',
  76. href: '/account/tokens',
  77. isActive:
  78. currentPath === '/account/tokens' || currentPath === '/account/tokens/scoped',
  79. },
  80. ...(showSecuritySettings
  81. ? [
  82. {
  83. key: 'security',
  84. label: 'Security',
  85. href: '/account/security',
  86. isActive: currentPath === '/account/security',
  87. },
  88. ]
  89. : []),
  90. ],
  91. },
  92. {
  93. key: 'logs',
  94. heading: 'Logs',
  95. links: [
  96. {
  97. key: 'audit-logs',
  98. label: 'Audit Logs',
  99. href: '/account/audit',
  100. isActive: currentPath === '/account/audit',
  101. },
  102. ],
  103. },
  104. ],
  105. [currentPath, showSecuritySettings]
  106. )
  107. useLayoutEffect(() => {
  108. const unregister = registerOpenMenu(() => {
  109. setMobileSheetContent(
  110. <AccountMenuContent sections={sections} onCloseSheet={() => setMobileSheetContent(null)} />
  111. )
  112. })
  113. return unregister
  114. }, [registerOpenMenu, setMobileSheetContent, sections])
  115. useEffect(() => {
  116. if (!IS_PLATFORM && currentPath !== '/account/me') {
  117. router.push('/project/default')
  118. }
  119. }, [currentPath, router])
  120. return (
  121. <>
  122. <Head>
  123. <title>{pageTitle}</title>
  124. <meta name="description" content="Briven Studio" />
  125. </Head>
  126. <div className={cn('flex flex-col w-screen h-[calc(100vh-48px)]')}>
  127. <WithSidebar backToDashboardURL={backToDashboardURL} sections={sections}>
  128. {children}
  129. </WithSidebar>
  130. </div>
  131. </>
  132. )
  133. }
  134. export default withAuth(AccountLayout)