import { ArrowUpDown, ChevronDown, Clock3, Cloud, FileClock, Folder as FolderIcon, KeyRound, Lock, LogOut, MonitorSmartphone, Send as SendIcon, Settings as SettingsIcon, ShieldCheck, ShieldUser, Sparkles, Users } from 'lucide-preact'; import type { ComponentChildren } from 'preact'; import { useState } from 'preact/hooks'; import { Link } from 'wouter'; import AppMainRoutes from '@/components/AppMainRoutes'; import NetworkStatusBadge from '@/components/NetworkStatusBadge'; import ThemeSwitch from '@/components/ThemeSwitch'; import type { AppMainRoutesProps } from '@/components/AppMainRoutes'; import { t } from '@/lib/i18n'; import type { Profile } from '@/lib/types'; interface AppAuthenticatedShellProps { profile: Profile | null; location: string; mobilePrimaryRoute: string; currentPageTitle: string; showSidebarToggle: boolean; sidebarToggleTitle: string; settingsAccountRoute: string; importRoute: string; isImportRoute: boolean; darkMode: boolean; themeToggleTitle: string; onLock: () => void; onLogout: () => void; onToggleTheme: () => void; onToggleMobileSidebar: () => void; mainRoutesProps: AppMainRoutesProps; } const NAV_GROUPS_STORAGE_KEY = 'nodewarden.navGroups'; const DEFAULT_EXPANDED_GROUPS = { tools: true, settings: true, management: true, }; type NavGroup = keyof typeof DEFAULT_EXPANDED_GROUPS; type ExpandedGroups = Record; function readExpandedGroups(): ExpandedGroups { if (typeof window === 'undefined') return DEFAULT_EXPANDED_GROUPS; try { const saved = window.localStorage.getItem(NAV_GROUPS_STORAGE_KEY); if (!saved) return DEFAULT_EXPANDED_GROUPS; const parsed = JSON.parse(saved) as Partial; return { tools: typeof parsed.tools === 'boolean' ? parsed.tools : DEFAULT_EXPANDED_GROUPS.tools, settings: typeof parsed.settings === 'boolean' ? parsed.settings : DEFAULT_EXPANDED_GROUPS.settings, management: typeof parsed.management === 'boolean' ? parsed.management : DEFAULT_EXPANDED_GROUPS.management, }; } catch { // Ignore local preference read failures. } return DEFAULT_EXPANDED_GROUPS; } function isAdminProfile(profile: Profile | null): boolean { return String(profile?.role || '').toLowerCase() === 'admin'; } const DEVICE_MANAGEMENT_ROUTE = '/settings/security/device-management'; const LEGACY_DEVICE_MANAGEMENT_ROUTE = '/security/devices'; export default function AppAuthenticatedShell(props: AppAuthenticatedShellProps) { const routeAnimationKey = props.isImportRoute ? props.importRoute : props.location; const isDomainRulesRoute = props.location === '/settings/domain-rules'; const isLogRoute = props.location === '/logs'; const isAdmin = isAdminProfile(props.profile); const deviceManagementActive = props.location === DEVICE_MANAGEMENT_ROUTE || props.location === LEGACY_DEVICE_MANAGEMENT_ROUTE; const [expandedGroups, setExpandedGroups] = useState(readExpandedGroups); function toggleGroup(group: NavGroup): void { setExpandedGroups((current) => { const next = { ...current, [group]: !current[group] }; try { window.localStorage.setItem(NAV_GROUPS_STORAGE_KEY, JSON.stringify(next)); } catch { // Ignore local preference write failures. } return next; }); } function renderSideLink(href: string, active: boolean, icon: ComponentChildren, label: string) { return ( {icon} {label} ); } function renderSubLink(href: string, active: boolean, label: string) { return ( {label} ); } function renderNavGroup( group: NavGroup, title: string, icon: ComponentChildren, children: ComponentChildren ) { const open = expandedGroups[group]; return (
{children}
); } const groupedNav = ( <> {renderSideLink('/vault', props.location === '/vault', , t('nav_vault_items'))} {renderSideLink('/sends', props.location === '/sends', , t('nav_sends'))} {renderNavGroup( 'tools', t('nav_group_tools'), , <> {renderSubLink('/vault/totp', props.location === '/vault/totp', t('txt_verification_code'))} {renderSubLink('/generator', props.location === '/generator', t('nav_generator'))} {renderSubLink('/security/password-health', props.location === '/security/password-health', t('nav_password_security'))} {renderSubLink(props.importRoute, props.isImportRoute, t('nav_import_export'))} )} {renderNavGroup( 'settings', t('txt_settings'), , <> {renderSubLink(props.settingsAccountRoute, props.location === props.settingsAccountRoute, t('nav_account_settings'))} {renderSubLink(DEVICE_MANAGEMENT_ROUTE, deviceManagementActive, t('nav_device_management'))} {renderSubLink('/settings/domain-rules', props.location === '/settings/domain-rules', t('nav_domain_rules'))} )} {isAdmin && renderNavGroup( 'management', t('nav_group_system_management'), , <> {renderSubLink('/backup', props.location === '/backup', t('nav_backup_strategy'))} {renderSubLink('/admin', props.location === '/admin', t('nav_admin_panel'))} {renderSubLink('/logs', props.location === '/logs', t('nav_log_center'))} )} ); return (
NodeWarden logo {props.currentPageTitle}
{props.profile?.email}
{props.showSidebarToggle && ( )}
); }