@@ -50,6 +50,7 @@ import { useTranslator } from "@/hooks/use-translations";
5050import { secureSetItem } from '@/libs/local-storage-utils' ;
5151import { SearchModal } from "@/components/search-modal" ;
5252import { logout } from "@/libs/utils" ;
53+ import { SidebarNav } from "@/components/sidebar-nav" ;
5354
5455interface DashboardLayoutProps {
5556 children : React . ReactNode ;
@@ -345,14 +346,7 @@ export function DashboardLayout({ children, locale = "en" }: DashboardLayoutProp
345346 const [ showFavoritesDialog , setShowFavoritesDialog ] = useState ( false ) ;
346347 const [ favoriteTags , setFavoriteTags ] = useState ( [ "Personal" , "Work" , "Banking" ] ) ;
347348 const [ showSearchModal , setShowSearchModal ] = useState ( false ) ;
348-
349- const [ collapsedCategories , setCollapsedCategories ] = useState < Record < string , boolean > > ( {
350- overview : false ,
351- general : false ,
352- security : false ,
353- business : false ,
354- licenses : false
355- } ) ;
349+ const [ currentLocale , setCurrentLocale ] = useState ( locale ) ;
356350
357351 const languageLabels : Record < string , string > = {
358352 af : "Afrikaans" ,
@@ -388,45 +382,11 @@ export function DashboardLayout({ children, locale = "en" }: DashboardLayoutProp
388382 "zh-Hant" : "Chinese Traditional (繁體中文)" ,
389383 } ;
390384
391- const selectedWorkspaceId = useSelector ( ( state : RootState ) => state . workspace . selectedWorkspaceId ) ;
392- const selectedProjectId = useSelector ( ( state : RootState ) => state . workspace . selectedProjectId ) ;
393- const selectedProject = useSelector ( ( state : RootState ) =>
394- Array . isArray ( state . workspace . workspaces ) && selectedWorkspaceId && selectedProjectId
395- ? state . workspace . workspaces
396- . find ( ( ws ) => ws . workspaceId === selectedWorkspaceId )
397- ?. projects . find ( ( p ) => p . project_id === selectedProjectId )
398- : null
399- ) ;
400- const defaultProject = useSelector ( ( state : RootState ) =>
401- Array . isArray ( state . workspace . workspaces ) && selectedWorkspaceId
402- ? state . workspace . workspaces
403- . find ( ( ws ) => ws . workspaceId === selectedWorkspaceId )
404- ?. projects . find ( ( p ) => p . is_default )
405- : null
406- ) ;
407- const displayProject = selectedProject || defaultProject ;
408-
409- const normalizedFeatures = displayProject
410- ? { ...defaultFeatures , ...( displayProject . features || { } ) }
411- : defaultFeatures ;
412-
413- const selectedWorkspace = useSelector ( ( state : RootState ) =>
414- Array . isArray ( state . workspace . workspaces )
415- ? state . workspace . workspaces . find ( ( ws ) => ws . workspaceId === selectedWorkspaceId )
416- : null
417- ) ;
418- const workspaceName = selectedWorkspace ?. name || "Personal Workspace" ;
419-
420- const toggleCategory = ( categoryId : string ) => {
421- setCollapsedCategories ( prev => ( {
422- ...prev ,
423- [ categoryId ] : ! prev [ categoryId ]
424- } ) ) ;
425- } ;
426-
427- const removeTag = ( tagToRemove : string ) => {
428- setFavoriteTags ( favoriteTags . filter ( ( tag ) => tag !== tagToRemove ) ) ;
429- } ;
385+ const sortedLocales = [ ...locales ] . sort ( ( a , b ) => {
386+ const nameA = languageLabels [ a ] || a ;
387+ const nameB = languageLabels [ b ] || b ;
388+ return nameA . localeCompare ( nameB ) ;
389+ } ) ;
430390
431391 const handleLogout = async ( ) => {
432392 await logout ( {
@@ -450,8 +410,6 @@ export function DashboardLayout({ children, locale = "en" }: DashboardLayoutProp
450410 setCurrentLocale ( newLocale ) ;
451411 } ;
452412
453- const [ currentLocale , setCurrentLocale ] = useState ( locale ) ;
454-
455413 useEffect ( ( ) => {
456414 if ( locale ) {
457415 setCurrentLocale ( locale ) ;
@@ -607,185 +565,26 @@ export function DashboardLayout({ children, locale = "en" }: DashboardLayoutProp
607565 } ;
608566 } , [ currentLocale , router ] ) ;
609567
610- const sortedLocales = [ ...locales ] . sort ( ( a , b ) => {
611- const nameA = languageLabels [ a ] || a ;
612- const nameB = languageLabels [ b ] || b ;
613- return nameA . localeCompare ( nameB ) ;
614- } ) ;
615-
616- const enabledMenuItems : SearchModule [ ] = displayProject
617- ? navigationCategories . flatMap ( category =>
618- category . items . filter ( item =>
619- 'always_visible' in item ? item . always_visible :
620- 'feature_key' in item && item . feature_key && normalizedFeatures [ item . feature_key as keyof typeof defaultFeatures ] ?. enabled
621- ) . map ( item => ( {
622- key : 'feature_key' in item && item . feature_key ? item . feature_key : item . key ,
623- labelKey : item . labelKey ,
624- path : item . path ,
625- icon : item . icon
626- } ) )
627- )
628- : [ ] ;
629-
630- const getVisibleCategories = ( ) => {
631- return navigationCategories . map ( category => ( {
632- ...category ,
633- items : category . items . filter ( item =>
634- 'always_visible' in item ? item . always_visible :
635- 'feature_key' in item && item . feature_key && normalizedFeatures [ item . feature_key as keyof typeof defaultFeatures ] ?. enabled
636- )
637- } ) ) . filter ( category => category . items . length > 0 ) ;
638- } ;
639-
640- const visibleCategories = getVisibleCategories ( ) ;
641-
642568 return (
643569 < div className = "flex min-h-screen bg-background" >
644570 < SearchModal
645571 isOpen = { showSearchModal }
646572 onClose = { ( ) => setShowSearchModal ( false ) }
647- modules = { enabledMenuItems }
573+ modules = { [ ] }
648574 locale = { currentLocale }
649575 onSelectModule = { ( path ) => router . push ( `/${ currentLocale } ${ path } ` ) }
650576 />
651577
652- < div className = "hidden md:flex w-64 flex-col border-r border-border" >
653- < div className = "flex h-14 items-center border-b border-border px-4" >
654- < Link href = { `/${ currentLocale } /dashboard` } className = "flex items-center gap-2 font-semibold" >
655- < Lock className = "h-5 w-5" />
656- < span > Zecrypt</ span >
657- </ Link >
658- < div className = "ml-auto flex items-center gap-1" >
659- < Button
660- variant = "ghost"
661- size = "icon"
662- className = "h-8 w-8"
663- onClick = { ( ) => document . dispatchEvent ( new KeyboardEvent ( "keydown" , { key : "k" , metaKey : true } ) ) }
664- >
665- < Command className = "h-4 w-4" />
666- </ Button >
667- </ div >
668- </ div >
669-
670- < div className = "flex-1 overflow-auto py-2 flex flex-col" >
671- < div className = "px-3 py-2" >
672- < div className = "mb-4" >
673- < label className = "px-2 text-xs font-semibold text-muted-foreground mb-2 block" > { translate ( "project" , "dashboard" ) } </ label >
674- < Button
675- variant = "outline"
676- className = "w-full justify-between hover:bg-accent/50 transition-colors"
677- onClick = { ( ) => setShowProjectDialog ( true ) }
678- disabled = { ! selectedWorkspaceId }
679- >
680- < div className = "flex items-center gap-2 overflow-hidden" >
681- < div
682- className = "h-4 w-4 rounded-full"
683- style = { { backgroundColor : displayProject ?. color || "#4f46e5" } }
684- > </ div >
685- < span className = "truncate" > { displayProject ?. name || translate ( "no_project_selected" , "dashboard" ) } </ span >
686- </ div >
687- < ChevronDown className = "h-4 w-4 opacity-50" />
688- </ Button >
689- </ div >
690-
691- < div className = "space-y-4" >
692- < Link
693- href = { `/${ currentLocale } /dashboard` }
694- className = { cn (
695- "flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors" ,
696- pathname === `/${ currentLocale } /dashboard`
697- ? "bg-primary text-primary-foreground"
698- : "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
699- ) }
700- >
701- < Home className = "h-4 w-4" />
702- { translate ( "overview" , "dashboard" ) }
703- </ Link >
704-
705- { visibleCategories . map ( ( category ) => (
706- < div key = { category . id } >
707- < div className = "flex items-center justify-between mb-2" >
708- < h3 className = "px-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider" >
709- { translate ( category . labelKey , "dashboard" ) }
710- </ h3 >
711- < Button
712- variant = "ghost"
713- size = "sm"
714- className = "h-5 w-5 p-0 hover:bg-accent/50 transition-colors"
715- onClick = { ( ) => toggleCategory ( category . id ) }
716- >
717- { collapsedCategories [ category . id ] ? (
718- < ChevronRight className = "h-3 w-3" />
719- ) : (
720- < ChevronDown className = "h-3 w-3" />
721- ) }
722- </ Button >
723- </ div >
724- < div className = { cn (
725- "space-y-1 transition-all duration-200 ease-in-out overflow-hidden" ,
726- ! collapsedCategories [ category . id ]
727- ? "opacity-100 max-h-96"
728- : "opacity-0 max-h-0"
729- ) } >
730- { category . items . map ( ( item ) => (
731- < Link
732- key = { item . key }
733- href = { `/${ currentLocale } ${ item . path } ` }
734- className = { cn (
735- "flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors" ,
736- pathname === `/${ currentLocale } ${ item . path } `
737- ? "bg-primary text-primary-foreground"
738- : "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
739- ) }
740- >
741- { item . icon }
742- { translate ( item . labelKey , "dashboard" ) }
743- </ Link >
744- ) ) }
745- </ div >
746- </ div >
747- ) ) }
748- </ div >
749- </ div >
750-
751- < div className = "p-3 border-t border-border mt-auto" >
752- < DropdownMenu >
753- < DropdownMenuTrigger asChild >
754- < div className = "flex items-center gap-3 rounded-md px-2 py-1.5 cursor-pointer hover:bg-accent" >
755- < Avatar className = "h-8 w-8" >
756- < AvatarImage src = { user ?. profileImageUrl || "/placeholder.svg?height=32&width=32" } alt = { user ?. displayName || "User" } />
757- < AvatarFallback >
758- { user ?. displayName
759- ? user . displayName . split ( " " ) . map ( ( n ) => n [ 0 ] ) . join ( "" ) . toUpperCase ( ) . substring ( 0 , 2 )
760- : "U" }
761- </ AvatarFallback >
762- </ Avatar >
763- < div className = "overflow-hidden" >
764- < p className = "text-sm font-medium truncate" > { user ?. displayName || "User" } </ p >
765- < p className = "text-xs text-muted-foreground truncate" > { user ?. primaryEmail || "user@example.com" } </ p >
766- </ div >
767- < ChevronDown className = "ml-auto h-4 w-4" />
768- </ div >
769- </ DropdownMenuTrigger >
770- < DropdownMenuContent align = "end" className = "w-56" >
771- < DropdownMenuLabel > My Account</ DropdownMenuLabel >
772- < DropdownMenuSeparator />
773- < DropdownMenuItem asChild >
774- < Link href = { `/${ currentLocale } /dashboard/user-settings` } >
775- < Settings className = "mr-2 h-4 w-4" />
776- < span > { translate ( "settings" , "dashboard" ) } </ span >
777- </ Link >
778- </ DropdownMenuItem >
779- < DropdownMenuSeparator />
780- < DropdownMenuItem onClick = { handleLogout } >
781- < LogOut className = "mr-2 h-4 w-4" />
782- < span > { translate ( "logout" , "dashboard" ) } </ span >
783- </ DropdownMenuItem >
784- </ DropdownMenuContent >
785- </ DropdownMenu >
786- </ div >
787- </ div >
788- </ div >
578+ < SidebarNav
579+ currentLocale = { currentLocale }
580+ onGeneratePassword = { ( ) => setShowGeneratePassword ( true ) }
581+ onProjectDialog = { ( ) => setShowProjectDialog ( true ) }
582+ onLogout = { handleLogout }
583+ onLanguageChange = { switchLanguage }
584+ languageLabels = { languageLabels }
585+ sortedLocales = { sortedLocales }
586+ user = { user }
587+ />
789588
790589 < div className = "flex flex-1 flex-col" >
791590 < header className = "flex h-14 items-center gap-4 border-b border-border px-4 lg:px-6" >
@@ -830,11 +629,6 @@ export function DashboardLayout({ children, locale = "en" }: DashboardLayoutProp
830629 </ Tooltip >
831630 </ TooltipProvider >
832631
833- { /* <div className="flex items-center gap-2 px-3 py-1.5">
834- <Users className="h-4 w-4 text-muted-foreground" />
835- <span className="text-sm font-medium">{workspaceName}</span>
836- </div> */ }
837-
838632 < DropdownMenu >
839633 < DropdownMenuTrigger asChild >
840634 < Button variant = "ghost" size = "icon" className = "rounded-full h-8 w-8" >
@@ -874,7 +668,6 @@ export function DashboardLayout({ children, locale = "en" }: DashboardLayoutProp
874668
875669 { showGeneratePassword && < GeneratePasswordDialog onClose = { ( ) => setShowGeneratePassword ( false ) } /> }
876670 { showProjectDialog && < ProjectDialog onClose = { ( ) => setShowProjectDialog ( false ) } /> }
877- { /* <KeyboardShortcutsHelp /> */ }
878671 </ div >
879672 ) ;
880673}
0 commit comments