index.tsx 6.0 KB

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