Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { memo, useEffect, useRef, useState } from 'react'
import { memo, type ReactElement, useEffect, useRef, useState } from 'react'
import {
ChevronDown,
Chip,
Expand All @@ -14,6 +14,7 @@ import {
Plus,
Send,
Skeleton,
Tooltip,
} from '@sim/emcn'
import { ManageWorkspace, PanelLeft } from '@sim/emcn/icons'
import { createLogger } from '@sim/logger'
Expand All @@ -33,6 +34,27 @@ import { useSettingsNavigation } from '@/hooks/use-settings-navigation'

const logger = createLogger('WorkspaceHeader')

interface DisabledReasonTooltipProps {
reason: string | null
children: ReactElement
}

/**
* Wraps a menu item in a tooltip explaining why the action is unavailable.
* Renders the child as-is when there is no reason to show.
*/
function DisabledReasonTooltip({ reason, children }: DisabledReasonTooltipProps) {
if (!reason) return children
return (
<Tooltip.Root>
<Tooltip.Trigger asChild>{children}</Tooltip.Trigger>
<Tooltip.Content>
<p>{reason}</p>
</Tooltip.Content>
</Tooltip.Root>
)
}

interface WorkspaceHeaderProps {
/** The active workspace object */
activeWorkspace?: { name: string } | null
Expand Down Expand Up @@ -548,62 +570,67 @@ function WorkspaceHeaderImpl({
<DropdownMenuSeparator className='mx-0' />

<div className='flex flex-col gap-0.5'>
<DisabledReasonTooltip reason={createWorkspaceDisabledReason}>
<Chip
leftIcon={Plus}
onClick={(e) => {
e.stopPropagation()
if (!canCreateWorkspace) return
setIsWorkspaceMenuOpen(false)
setIsCreateModalOpen(true)
}}
disabled={isCreatingWorkspace}
aria-disabled={!canCreateWorkspace || undefined}
fullWidth
flush
className={cn(
'select-none',
!canCreateWorkspace &&
'cursor-not-allowed opacity-60 hover-hover:bg-transparent'
)}
>
New workspace
</Chip>
</DisabledReasonTooltip>
</div>

<DropdownMenuSeparator className='mx-0' />
<DisabledReasonTooltip reason={inviteDisabledReason}>
<Chip
leftIcon={Plus}
onClick={(e) => {
e.stopPropagation()
leftIcon={Send}
onClick={() => {
setIsWorkspaceMenuOpen(false)
if (!canCreateWorkspace) {
if (isInvitationsDisabled) {
if (isBillingEnabled) navigateToSettings({ section: 'billing' })
return
}
setIsCreateModalOpen(true)
setIsInviteModalOpen(true)
}}
disabled={isCreatingWorkspace}
title={createWorkspaceDisabledReason ?? undefined}
fullWidth
flush
className='w-full select-none disabled:pointer-events-none disabled:opacity-50'
className='select-none'
>
New workspace
Invite teammates
</Chip>
</div>

<DropdownMenuSeparator className='mx-0' />
<Chip
leftIcon={Send}
onClick={() => {
setIsWorkspaceMenuOpen(false)
if (isInvitationsDisabled) {
if (isBillingEnabled) navigateToSettings({ section: 'billing' })
return
}
setIsInviteModalOpen(true)
}}
title={inviteDisabledReason ?? undefined}
fullWidth
flush
className='w-full select-none'
>
Invite teammates
</Chip>
<Chip
leftIcon={ManageWorkspace}
onClick={() => {
setIsWorkspaceMenuOpen(false)
if (isInvitationsDisabled) {
if (isBillingEnabled) navigateToSettings({ section: 'billing' })
return
}
navigateToSettings({ section: 'teammates' })
}}
title={inviteDisabledReason ?? undefined}
fullWidth
flush
className='w-full select-none'
>
Manage workspace
</Chip>
</DisabledReasonTooltip>
<DisabledReasonTooltip reason={inviteDisabledReason}>
<Chip
leftIcon={ManageWorkspace}
onClick={() => {
setIsWorkspaceMenuOpen(false)
if (isInvitationsDisabled) {
if (isBillingEnabled) navigateToSettings({ section: 'billing' })
return
}
navigateToSettings({ section: 'teammates' })
}}
fullWidth
flush
className='select-none'
>
Manage workspace
</Chip>
</DisabledReasonTooltip>
</>
)}
</DropdownMenuContent>
Expand Down
Loading