1- import { useState } from 'react' ;
1+ import { useMemo , useState } from 'react' ;
22import { m } from '../../../paraglide/messages' ;
3- import { Icon } from '../../defguard-ui/components/Icon' ;
3+ import { Icon , IconKind } from '../../defguard-ui/components/Icon' ;
44import type { IconKindValue } from '../../defguard-ui/components/Icon/icon-types' ;
55import { IconButton } from '../../defguard-ui/components/IconButton/IconButton' ;
66import { useApp } from '../../hooks/useApp' ;
77import { useAuth } from '../../hooks/useAuth' ;
88import { NavLogo } from './assets/NavLogo' ;
99import './style.scss' ;
10+ import { useQuery } from '@tanstack/react-query' ;
1011import { Link , type LinkProps } from '@tanstack/react-router' ;
12+ import { type LicenseInfo , LicenseTier , type LicenseTierValue } from '../../api/types' ;
1113import { Fold } from '../../defguard-ui/components/Fold/Fold' ;
14+ import { TooltipContent } from '../../defguard-ui/providers/tooltip/TooltipContent' ;
15+ import { TooltipProvider } from '../../defguard-ui/providers/tooltip/TooltipContext' ;
16+ import { TooltipTrigger } from '../../defguard-ui/providers/tooltip/TooltipTrigger' ;
17+ import { isPresent } from '../../defguard-ui/utils/isPresent' ;
1218import { useTheme } from '../../hooks/theme/useTheme' ;
19+ import { getLicenseInfoQueryOptions } from '../../query' ;
20+ import { canUseBusinessFeature } from '../../utils/license' ;
1321
1422interface NavGroupProps {
1523 id : string ;
1624 label : string ;
1725 items : NavItemProps [ ] ;
26+ licenseInfo ?: LicenseInfo | null ;
1827}
1928
2029interface NavItemProps {
2130 id : string ;
2231 label : string ;
2332 icon : IconKindValue ;
2433 link : LinkProps [ 'to' ] ;
34+ licenseTier ?: LicenseTierValue ;
35+ license ?: LicenseInfo | null ;
2536 testId ?: string ;
2637}
2738
@@ -72,18 +83,21 @@ const navigationConfig: NavGroupProps[] = [
7283 icon : 'rules' ,
7384 label : m . cmp_nav_item_rules ( ) ,
7485 link : '/acl/rules' ,
86+ licenseTier : LicenseTier . Business ,
7587 } ,
7688 {
7789 id : 'destinations' ,
7890 icon : 'gateway' ,
7991 label : m . cmp_nav_item_destinations ( ) ,
8092 link : '/acl/destinations' ,
93+ licenseTier : LicenseTier . Business ,
8194 } ,
8295 {
8396 id : 'aliases' ,
8497 icon : 'access-settings' ,
8598 label : m . cmp_nav_item_aliases ( ) ,
8699 link : '/acl/aliases' ,
100+ licenseTier : LicenseTier . Business ,
87101 } ,
88102 ] ,
89103 } ,
@@ -141,6 +155,11 @@ export const Navigation = () => {
141155 const isAdmin = useAuth ( ( s ) => s . isAdmin ) ;
142156 const isOpen = useApp ( ( s ) => s . navigationOpen ) ;
143157
158+ const { data : licenseInfo } = useQuery ( {
159+ ...getLicenseInfoQueryOptions ,
160+ enabled : isAdmin ,
161+ } ) ;
162+
144163 if ( ! isAdmin || ! isOpen ) return null ;
145164 return (
146165 < div className = "navigation" >
@@ -159,7 +178,7 @@ export const Navigation = () => {
159178 </ div >
160179 < div className = "groups" >
161180 { navigationConfig . map ( ( group ) => (
162- < NavGroup key = { group . id } { ...group } />
181+ < NavGroup key = { group . id } { ...group } licenseInfo = { licenseInfo } />
163182 ) ) }
164183 </ div >
165184 < div className = "bottom" >
@@ -169,7 +188,7 @@ export const Navigation = () => {
169188 ) ;
170189} ;
171190
172- const NavGroup = ( { items, label } : NavGroupProps ) => {
191+ const NavGroup = ( { items, label, licenseInfo } : NavGroupProps ) => {
173192 const [ isOpen , setIsOpen ] = useState ( true ) ;
174193 return (
175194 < div className = "nav-group" >
@@ -185,19 +204,47 @@ const NavGroup = ({ items, label }: NavGroupProps) => {
185204 < Fold open = { isOpen } >
186205 < div className = "items" >
187206 { items . map ( ( item ) => (
188- < NavItem key = { item . id } { ...item } />
207+ < NavItem key = { item . id } { ...item } license = { licenseInfo } />
189208 ) ) }
190209 </ div >
191210 </ Fold >
192211 </ div >
193212 ) ;
194213} ;
195214
196- const NavItem = ( { icon, link, label, testId } : NavItemProps ) => {
215+ const NavItem = ( { icon, link, label, testId, license, licenseTier } : NavItemProps ) => {
216+ const showLock = useMemo ( ( ) => {
217+ if ( licenseTier === undefined ) {
218+ return isPresent ( licenseTier ) ;
219+ }
220+
221+ if ( licenseTier !== undefined && licenseTier === LicenseTier . Business ) {
222+ return ! canUseBusinessFeature ( license as LicenseInfo | null ) . result ;
223+ }
224+
225+ if ( licenseTier !== undefined && licenseTier === LicenseTier . Enterprise ) {
226+ return ! canUseBusinessFeature ( license as LicenseInfo | null ) . result ;
227+ }
228+
229+ return false ;
230+ } , [ license , licenseTier ] ) ;
231+
197232 return (
198233 < Link to = { link } className = "nav-item" data-testid = { testId } >
199234 < Icon icon = { icon } />
200235 < span > { label } </ span >
236+ { showLock && isPresent ( licenseTier ) && (
237+ < div className = "right" >
238+ < TooltipProvider >
239+ < TooltipTrigger >
240+ < Icon icon = { IconKind . LockClosed } size = { 16 } />
241+ </ TooltipTrigger >
242+ < TooltipContent >
243+ < p > { `This is ${ licenseTier ?? 'Unknown tier' } feature` } </ p >
244+ </ TooltipContent >
245+ </ TooltipProvider >
246+ </ div >
247+ ) }
201248 </ Link >
202249 ) ;
203250} ;
0 commit comments