import { useEffect, useState, useRef } from 'react'; import { Routes, Route, Link, useLocation, Navigate, useParams } from 'react-router-dom'; import { clsx } from 'clsx'; import SearchDashboard from './components/SearchDashboard'; import Dashboard from './components/Dashboard'; import ApplicationList from './components/ApplicationList'; import ApplicationInfo from './components/ApplicationInfo'; import GovernanceModelHelper from './components/GovernanceModelHelper'; import TeamDashboard from './components/TeamDashboard'; import ConfigurationV25 from './components/ConfigurationV25'; import ReportsDashboard from './components/ReportsDashboard'; import GovernanceAnalysis from './components/GovernanceAnalysis'; import DataModelDashboard from './components/DataModelDashboard'; import FTECalculator from './components/FTECalculator'; import Login from './components/Login'; import { useAuthStore } from './stores/authStore'; // Redirect component for old app-components/overview/:id paths function RedirectToApplicationEdit() { const { id } = useParams<{ id: string }>(); return ; } // Dropdown menu item type interface NavItem { path: string; label: string; exact?: boolean; } interface NavDropdown { label: string; icon?: React.ReactNode; items: NavItem[]; basePath: string; } // Dropdown component for navigation function NavDropdown({ dropdown, isActive }: { dropdown: NavDropdown; isActive: boolean }) { const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); const location = useLocation(); // Close dropdown when clicking outside useEffect(() => { function handleClickOutside(event: MouseEvent) { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false); } } document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); // Close dropdown on route change useEffect(() => { setIsOpen(false); }, [location.pathname]); return (
{isOpen && (
{dropdown.items.map((item) => { const itemActive = item.exact ? location.pathname === item.path : location.pathname.startsWith(item.path); return ( {item.label} ); })}
)}
); } function UserMenu() { const { user, authMethod, logout } = useAuthStore(); const [isOpen, setIsOpen] = useState(false); if (!user) return null; const initials = user.displayName .split(' ') .map(n => n[0]) .join('') .toUpperCase() .slice(0, 2); return (
{isOpen && ( <>
setIsOpen(false)} />

{user.displayName}

{user.emailAddress && (

{user.emailAddress}

)}

{authMethod === 'oauth' ? 'Jira OAuth' : 'Service Account'}

{authMethod === 'oauth' && ( )}
)}
); } function AppContent() { const location = useLocation(); // Navigation structure const appComponentsDropdown: NavDropdown = { label: 'Application Component', basePath: '/application', items: [ { path: '/app-components', label: 'Dashboard', exact: true }, { path: '/application/overview', label: 'Overzicht', exact: false }, { path: '/application/fte-calculator', label: 'FTE Calculator', exact: true }, { path: '/app-components/fte-config', label: 'FTE Config', exact: true }, ], }; const reportsDropdown: NavDropdown = { label: 'Rapporten', basePath: '/reports', items: [ { path: '/reports', label: 'Overzicht', exact: true }, { path: '/reports/team-dashboard', label: 'Team-indeling', exact: true }, { path: '/reports/governance-analysis', label: 'Analyse Regiemodel', exact: true }, { path: '/reports/data-model', label: 'Datamodel', exact: true }, ], }; const isAppComponentsActive = location.pathname.startsWith('/app-components') || location.pathname.startsWith('/application'); const isReportsActive = location.pathname.startsWith('/reports'); const isDashboardActive = location.pathname === '/'; return (
{/* Header */}
Zuyderland

Analyse Tool

Zuyderland CMDB

{/* Main content */}
{/* Main Dashboard (Search) */} } /> {/* Application routes (new structure) */} } /> } /> } /> } /> {/* Application Component routes */} } /> } /> {/* Reports routes */} } /> } /> } /> } /> {/* Legacy redirects for bookmarks - redirect old paths to new ones */} } /> } /> } /> } /> } /> } />
); } function App() { const { isAuthenticated, isLoading, checkAuth, fetchConfig, config } = useAuthStore(); useEffect(() => { // Fetch auth config first, then check auth status const init = async () => { await fetchConfig(); await checkAuth(); }; init(); }, [fetchConfig, checkAuth]); // Show loading state if (isLoading) { return (

Laden...

); } // Show login if OAuth is enabled and not authenticated if (config?.authMethod === 'oauth' && !isAuthenticated) { return ; } // Show login if nothing is configured if (config?.authMethod === 'none') { return ; } // Show main app return ; } export default App;