11'use client'
22
3- import { memo , useEffect , useRef , useState } from 'react'
3+ import { memo , type ReactElement , useEffect , useRef , useState } from 'react'
44import {
55 ChevronDown ,
66 Chip ,
@@ -14,6 +14,7 @@ import {
1414 Plus ,
1515 Send ,
1616 Skeleton ,
17+ Tooltip ,
1718} from '@sim/emcn'
1819import { ManageWorkspace , PanelLeft } from '@sim/emcn/icons'
1920import { createLogger } from '@sim/logger'
@@ -33,6 +34,27 @@ import { useSettingsNavigation } from '@/hooks/use-settings-navigation'
3334
3435const logger = createLogger ( 'WorkspaceHeader' )
3536
37+ interface DisabledReasonTooltipProps {
38+ reason : string | null
39+ children : ReactElement
40+ }
41+
42+ /**
43+ * Wraps a menu item in a tooltip explaining why the action is unavailable.
44+ * Renders the child as-is when there is no reason to show.
45+ */
46+ function DisabledReasonTooltip ( { reason, children } : DisabledReasonTooltipProps ) {
47+ if ( ! reason ) return children
48+ return (
49+ < Tooltip . Root >
50+ < Tooltip . Trigger asChild > { children } </ Tooltip . Trigger >
51+ < Tooltip . Content >
52+ < p > { reason } </ p >
53+ </ Tooltip . Content >
54+ </ Tooltip . Root >
55+ )
56+ }
57+
3658interface WorkspaceHeaderProps {
3759 /** The active workspace object */
3860 activeWorkspace ?: { name : string } | null
@@ -548,62 +570,67 @@ function WorkspaceHeaderImpl({
548570 < DropdownMenuSeparator className = 'mx-0' />
549571
550572 < div className = 'flex flex-col gap-0.5' >
573+ < DisabledReasonTooltip reason = { createWorkspaceDisabledReason } >
574+ < Chip
575+ leftIcon = { Plus }
576+ onClick = { ( e ) => {
577+ e . stopPropagation ( )
578+ if ( ! canCreateWorkspace ) return
579+ setIsWorkspaceMenuOpen ( false )
580+ setIsCreateModalOpen ( true )
581+ } }
582+ disabled = { isCreatingWorkspace }
583+ aria-disabled = { ! canCreateWorkspace || undefined }
584+ fullWidth
585+ flush
586+ className = { cn (
587+ 'select-none' ,
588+ ! canCreateWorkspace &&
589+ 'cursor-not-allowed opacity-60 hover-hover:bg-transparent'
590+ ) }
591+ >
592+ New workspace
593+ </ Chip >
594+ </ DisabledReasonTooltip >
595+ </ div >
596+
597+ < DropdownMenuSeparator className = 'mx-0' />
598+ < DisabledReasonTooltip reason = { inviteDisabledReason } >
551599 < Chip
552- leftIcon = { Plus }
553- onClick = { ( e ) => {
554- e . stopPropagation ( )
600+ leftIcon = { Send }
601+ onClick = { ( ) => {
555602 setIsWorkspaceMenuOpen ( false )
556- if ( ! canCreateWorkspace ) {
603+ if ( isInvitationsDisabled ) {
557604 if ( isBillingEnabled ) navigateToSettings ( { section : 'billing' } )
558605 return
559606 }
560- setIsCreateModalOpen ( true )
607+ setIsInviteModalOpen ( true )
561608 } }
562- disabled = { isCreatingWorkspace }
563- title = { createWorkspaceDisabledReason ?? undefined }
564609 fullWidth
565610 flush
566- className = 'w-full select-none disabled:pointer-events-none disabled:opacity-50 '
611+ className = 'select-none'
567612 >
568- New workspace
613+ Invite teammates
569614 </ Chip >
570- </ div >
571-
572- < DropdownMenuSeparator className = 'mx-0' />
573- < Chip
574- leftIcon = { Send }
575- onClick = { ( ) => {
576- setIsWorkspaceMenuOpen ( false )
577- if ( isInvitationsDisabled ) {
578- if ( isBillingEnabled ) navigateToSettings ( { section : 'billing' } )
579- return
580- }
581- setIsInviteModalOpen ( true )
582- } }
583- title = { inviteDisabledReason ?? undefined }
584- fullWidth
585- flush
586- className = 'w-full select-none'
587- >
588- Invite teammates
589- </ Chip >
590- < Chip
591- leftIcon = { ManageWorkspace }
592- onClick = { ( ) => {
593- setIsWorkspaceMenuOpen ( false )
594- if ( isInvitationsDisabled ) {
595- if ( isBillingEnabled ) navigateToSettings ( { section : 'billing' } )
596- return
597- }
598- navigateToSettings ( { section : 'teammates' } )
599- } }
600- title = { inviteDisabledReason ?? undefined }
601- fullWidth
602- flush
603- className = 'w-full select-none'
604- >
605- Manage workspace
606- </ Chip >
615+ </ DisabledReasonTooltip >
616+ < DisabledReasonTooltip reason = { inviteDisabledReason } >
617+ < Chip
618+ leftIcon = { ManageWorkspace }
619+ onClick = { ( ) => {
620+ setIsWorkspaceMenuOpen ( false )
621+ if ( isInvitationsDisabled ) {
622+ if ( isBillingEnabled ) navigateToSettings ( { section : 'billing' } )
623+ return
624+ }
625+ navigateToSettings ( { section : 'teammates' } )
626+ } }
627+ fullWidth
628+ flush
629+ className = 'select-none'
630+ >
631+ Manage workspace
632+ </ Chip >
633+ </ DisabledReasonTooltip >
607634 </ >
608635 ) }
609636 </ DropdownMenuContent >
0 commit comments