index.tsx 4.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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="min-w-0">
  32. {
  33. ({ open }) => (
  34. <>
  35. <MenuButton className={cn(
  36. `
  37. group flex w-full cursor-pointer items-center
  38. p-0.5 hover:bg-state-base-hover ${open && 'bg-state-base-hover'} rounded-[10px]
  39. `,
  40. )}>
  41. <div className='mr-1.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px] max-[800px]:mr-0'>
  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 min-w-0 items-center'>
  45. <div className={'system-sm-medium min-w-0 max-w-[149px] truncate text-text-secondary max-[800px]:hidden'}>{currentWorkspace?.name}</div>
  46. <RiArrowDownSLine className='h-4 w-4 shrink-0 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. anchor="bottom start"
  60. className={cn(
  61. `
  62. shadows-shadow-lg absolute left-[-15px] z-[1000] mt-1 flex max-h-[400px] w-[280px] flex-col items-start overflow-y-auto
  63. rounded-xl bg-components-panel-bg-blur backdrop-blur-[5px]
  64. `,
  65. )}
  66. >
  67. <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 ">
  68. <div className='flex items-start self-stretch px-3 pb-0.5 pt-1'>
  69. <span className='system-xs-medium-uppercase flex-1 text-text-tertiary'>{t('common.userProfile.workspace')}</span>
  70. </div>
  71. {
  72. workspaces.map(workspace => (
  73. <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)}>
  74. <div className='flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-components-icon-bg-blue-solid text-[13px]'>
  75. <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>
  76. </div>
  77. <div className='system-md-regular line-clamp-1 grow cursor-pointer overflow-hidden text-ellipsis text-text-secondary'>{workspace.name}</div>
  78. <PlanBadge plan={workspace.plan as Plan} />
  79. </div>
  80. ))
  81. }
  82. </div>
  83. </MenuItems>
  84. </Transition>
  85. </>
  86. )
  87. }
  88. </Menu>
  89. )
  90. }
  91. export default WorkplaceSelector