index.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. 'use client'
  2. import { useTranslation } from 'react-i18next'
  3. import { useEffect, useRef, useState } from 'react'
  4. import cn from 'classnames'
  5. import { AtSymbolIcon, CubeTransparentIcon, GlobeAltIcon, UserIcon, UsersIcon, XMarkIcon } from '@heroicons/react/24/outline'
  6. import { GlobeAltIcon as GlobalAltIconSolid, UserIcon as UserIconSolid, UsersIcon as UsersIconSolid } from '@heroicons/react/24/solid'
  7. import AccountPage from './account-page'
  8. import MembersPage from './members-page'
  9. import IntegrationsPage from './Integrations-page'
  10. import LanguagePage from './language-page'
  11. import ProviderPage from './provider-page'
  12. import DataSourcePage from './data-source-page'
  13. import s from './index.module.css'
  14. import Modal from '@/app/components/base/modal'
  15. import { Database03 } from '@/app/components/base/icons/src/vender/line/development'
  16. import { Database03 as Database03Solid } from '@/app/components/base/icons/src/vender/solid/development'
  17. const iconClassName = `
  18. w-4 h-4 ml-3 mr-2
  19. `
  20. const scrolledClassName = `
  21. border-b shadow-xs bg-white/[.98]
  22. `
  23. type IAccountSettingProps = {
  24. onCancel: () => void
  25. activeTab?: string
  26. }
  27. export default function AccountSetting({
  28. onCancel,
  29. activeTab = 'account',
  30. }: IAccountSettingProps) {
  31. const [activeMenu, setActiveMenu] = useState(activeTab)
  32. const { t } = useTranslation()
  33. const menuItems = [
  34. {
  35. key: 'account-group',
  36. name: t('common.settings.accountGroup'),
  37. items: [
  38. {
  39. key: 'account',
  40. name: t('common.settings.account'),
  41. icon: <UserIcon className={iconClassName} />,
  42. activeIcon: <UserIconSolid className={iconClassName} />,
  43. },
  44. {
  45. key: 'integrations',
  46. name: t('common.settings.integrations'),
  47. icon: <AtSymbolIcon className={iconClassName} />,
  48. activeIcon: <AtSymbolIcon className={iconClassName} />,
  49. },
  50. {
  51. key: 'language',
  52. name: t('common.settings.language'),
  53. icon: <GlobeAltIcon className={iconClassName} />,
  54. activeIcon: <GlobalAltIconSolid className={iconClassName} />,
  55. },
  56. ],
  57. },
  58. {
  59. key: 'workspace-group',
  60. name: t('common.settings.workplaceGroup'),
  61. items: [
  62. {
  63. key: 'members',
  64. name: t('common.settings.members'),
  65. icon: <UsersIcon className={iconClassName} />,
  66. activeIcon: <UsersIconSolid className={iconClassName} />,
  67. },
  68. {
  69. key: 'provider',
  70. name: t('common.settings.provider'),
  71. icon: <CubeTransparentIcon className={iconClassName} />,
  72. activeIcon: <CubeTransparentIcon className={iconClassName} />,
  73. },
  74. {
  75. key: 'data-source',
  76. name: t('common.settings.dataSource'),
  77. icon: <Database03 className={iconClassName} />,
  78. activeIcon: <Database03Solid className={iconClassName} />,
  79. },
  80. ],
  81. },
  82. ]
  83. const scrollRef = useRef<HTMLDivElement>(null)
  84. const [scrolled, setScrolled] = useState(false)
  85. const scrollHandle = (e: any) => {
  86. if (e.target.scrollTop > 0)
  87. setScrolled(true)
  88. else
  89. setScrolled(false)
  90. }
  91. useEffect(() => {
  92. const targetElement = scrollRef.current
  93. targetElement?.addEventListener('scroll', scrollHandle)
  94. return () => {
  95. targetElement?.removeEventListener('scroll', scrollHandle)
  96. }
  97. }, [])
  98. return (
  99. <Modal
  100. isShow
  101. onClose={() => { }}
  102. className={s.modal}
  103. wrapperClassName='pt-[60px]'
  104. >
  105. <div className='flex'>
  106. <div className='w-[200px] p-4 border border-gray-100'>
  107. <div className='mb-8 ml-2 text-base font-medium leading-6 text-gray-900'>{t('common.userProfile.settings')}</div>
  108. <div>
  109. {
  110. menuItems.map(menuItem => (
  111. <div key={menuItem.key} className='mb-4'>
  112. <div className='px-2 mb-[6px] text-xs font-medium text-gray-500'>{menuItem.name}</div>
  113. <div>
  114. {
  115. menuItem.items.map(item => (
  116. <div
  117. key={item.key}
  118. className={`
  119. flex items-center h-[37px] mb-[2px] text-sm cursor-pointer rounded-lg
  120. ${activeMenu === item.key ? 'font-semibold text-primary-600 bg-primary-50' : 'font-light text-gray-700'}
  121. `}
  122. onClick={() => setActiveMenu(item.key)}
  123. >
  124. {activeMenu === item.key ? item.activeIcon : item.icon}{item.name}
  125. </div>
  126. ))
  127. }
  128. </div>
  129. </div>
  130. ))
  131. }
  132. </div>
  133. </div>
  134. <div ref={scrollRef} className='relative w-[520px] h-[580px] pb-4 overflow-y-auto'>
  135. <div className={cn('sticky top-0 px-6 py-4 flex items-center justify-between h-14 mb-4 bg-white text-base font-medium text-gray-900', scrolled && scrolledClassName)}>
  136. {[...menuItems[0].items, ...menuItems[1].items].find(item => item.key === activeMenu)?.name}
  137. <XMarkIcon className='w-4 h-4 cursor-pointer' onClick={onCancel} />
  138. </div>
  139. <div className='px-6'>
  140. {activeMenu === 'account' && <AccountPage />}
  141. {activeMenu === 'members' && <MembersPage />}
  142. {activeMenu === 'integrations' && <IntegrationsPage />}
  143. {activeMenu === 'language' && <LanguagePage />}
  144. {activeMenu === 'provider' && <ProviderPage />}
  145. {activeMenu === 'data-source' && <DataSourcePage />}
  146. </div>
  147. </div>
  148. </div>
  149. </Modal>
  150. )
  151. }