You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.tsx 4.6KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import { Fragment } from 'react'
  2. import { useContext } from 'use-context-selector'
  3. import { useTranslation } from 'react-i18next'
  4. import { Menu, MenuButton, MenuItems, Transition } from '@headlessui/react'
  5. import { RiArrowDownSLine } from '@remixicon/react'
  6. import cn from '@/utils/classnames'
  7. import { basePath } from '@/utils/var'
  8. import PlanBadge from '@/app/components/header/plan-badge'
  9. import { switchWorkspace } from '@/service/common'
  10. import { useWorkspacesContext } from '@/context/workspace-context'
  11. import { ToastContext } from '@/app/components/base/toast'
  12. import type { Plan } from '@/app/components/billing/type'
  13. const WorkplaceSelector = () => {
  14. const { t } = useTranslation()
  15. const { notify } = useContext(ToastContext)
  16. const { workspaces } = useWorkspacesContext()
  17. const currentWorkspace = workspaces.find(v => v.current)
  18. const handleSwitchWorkspace = async (tenant_id: string) => {
  19. try {
  20. if (currentWorkspace?.id === tenant_id)
  21. return
  22. await switchWorkspace({ url: '/workspaces/switch', body: { tenant_id } })
  23. notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
  24. location.assign(`${location.origin}${basePath}`)
  25. }
  26. catch {
  27. notify({ type: 'error', message: t('common.provider.saveFailed') })
  28. }
  29. }
  30. return (
  31. <Menu as="div" className="relative h-full w-full">
  32. {
  33. ({ open }) => (
  34. <>
  35. <MenuButton className={cn(
  36. `
  37. group flex w-full cursor-pointer items-center
  38. gap-1.5 p-0.5 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} rounded-[10px]
  39. `,
  40. )}>
  41. <div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
  42. <span className='h-6 bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text align-middle font-semibold uppercase leading-6 text-shadow-shadow-1 opacity-90'>{currentWorkspace?.name[0]?.toLocaleUpperCase()}</span>
  43. </div>
  44. <div className='flex flex-row'>
  45. <div className={'system-sm-medium max-w-[160px] truncate text-text-secondary'}>{currentWorkspace?.name}</div>
  46. <RiArrowDownSLine className='h-4 w-4 text-text-secondary' />
  47. </div>
  48. </MenuButton>
  49. <Transition
  50. as={Fragment}
  51. enter="transition ease-out duration-100"
  52. enterFrom="transform opacity-0 scale-95"
  53. enterTo="transform opacity-100 scale-100"
  54. leave="transition ease-in duration-75"
  55. leaveFrom="transform opacity-100 scale-100"
  56. leaveTo="transform opacity-0 scale-95"
  57. >
  58. <MenuItems
  59. className={cn(
  60. `
  61. shadows-shadow-lg absolute left-[-15px] mt-1 flex max-h-[400px] w-[280px] flex-col items-start overflow-y-auto rounded-xl
  62. bg-components-panel-bg-blur backdrop-blur-[5px]
  63. `,
  64. )}
  65. >
  66. <div className="flex w-full flex-col items-start self-stretch rounded-xl border-[0.5px] border-components-panel-border p-1 pb-2 shadow-lg ">
  67. <div className='flex items-start self-stretch px-3 pb-0.5 pt-1'>
  68. <span className='system-xs-medium-uppercase flex-1 text-text-tertiary'>{t('common.userProfile.workspace')}</span>
  69. </div>
  70. {
  71. workspaces.map(workspace => (
  72. <div className='flex items-center gap-2 self-stretch rounded-lg py-1 pl-3 pr-2 hover:bg-state-base-hover' key={workspace.id} onClick={() => handleSwitchWorkspace(workspace.id)}>
  73. <div className='flex h-6 w-6 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
  74. <span className='h-6 bg-gradient-to-r from-components-avatar-shape-fill-stop-0 to-components-avatar-shape-fill-stop-100 bg-clip-text align-middle font-semibold uppercase leading-6 text-shadow-shadow-1 opacity-90'>{workspace?.name[0]?.toLocaleUpperCase()}</span>
  75. </div>
  76. <div className='system-md-regular line-clamp-1 grow cursor-pointer overflow-hidden text-ellipsis text-text-secondary'>{workspace.name}</div>
  77. <PlanBadge plan={workspace.plan as Plan} />
  78. </div>
  79. ))
  80. }
  81. </div>
  82. </MenuItems>
  83. </Transition>
  84. </>
  85. )
  86. }
  87. </Menu>
  88. )
  89. }
  90. export default WorkplaceSelector