refactor(ui): Verwaltung-Dropdown aufgelöst – Berichte flach, Rest in /settings
Verwaltung-Dropdown entfernt. Berichte wandert flach in die Topbar (HR+). Mitarbeiter/Sondervertretungen/Auszahlung als Gruppe "Personal" und Mandanten als Gruppe "Mandant" auf der /settings-Kachelseite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { Link, useLocation, useNavigate } from 'react-router-dom'
|
import { Link, useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useAuth } from '../context/AuthContext'
|
import { useAuth } from '../context/AuthContext'
|
||||||
import { useState, useRef, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { api } from '../api/client'
|
import { api } from '../api/client'
|
||||||
import { PRIMARY_NAV, MANAGEMENT_NAV, visibleFor, hasAnySettings } from './navConfig'
|
import { PRIMARY_NAV, visibleFor, hasAnySettings } from './navConfig'
|
||||||
|
|
||||||
interface KioskHealthDevice {
|
interface KioskHealthDevice {
|
||||||
status: 'pending' | 'approved' | 'revoked'
|
status: 'pending' | 'approved' | 'revoked'
|
||||||
@@ -80,27 +80,13 @@ export function Layout({ children, userRole, userName }: {
|
|||||||
}) {
|
}) {
|
||||||
const { logout } = useAuth()
|
const { logout } = useAuth()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const [mgmtOpen, setMgmtOpen] = useState(false)
|
|
||||||
const mgmtRef = useRef<HTMLDivElement>(null)
|
|
||||||
|
|
||||||
const visiblePrimary = visibleFor(PRIMARY_NAV, userRole)
|
const visiblePrimary = visibleFor(PRIMARY_NAV, userRole)
|
||||||
const visibleMgmt = visibleFor(MANAGEMENT_NAV, userRole)
|
|
||||||
const isMgmtActive = visibleMgmt.some(n => pathname === n.path)
|
|
||||||
const settingsActive = pathname.startsWith('/settings') ||
|
const settingsActive = pathname.startsWith('/settings') ||
|
||||||
['/work-schedules', '/users/import'].includes(pathname)
|
['/work-schedules', '/users/import', '/users', '/hr/special-assignments',
|
||||||
|
'/hr/payouts', '/admin/tenants'].includes(pathname)
|
||||||
const showSettings = hasAnySettings(userRole)
|
const showSettings = hasAnySettings(userRole)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function handleClick(e: MouseEvent) {
|
|
||||||
if (mgmtRef.current && !mgmtRef.current.contains(e.target as Node))
|
|
||||||
setMgmtOpen(false)
|
|
||||||
}
|
|
||||||
if (mgmtOpen) document.addEventListener('mousedown', handleClick)
|
|
||||||
return () => document.removeEventListener('mousedown', handleClick)
|
|
||||||
}, [mgmtOpen])
|
|
||||||
|
|
||||||
useEffect(() => { setMgmtOpen(false) }, [pathname])
|
|
||||||
|
|
||||||
const initials = userName
|
const initials = userName
|
||||||
? userName.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase()
|
? userName.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase()
|
||||||
: '?'
|
: '?'
|
||||||
@@ -133,44 +119,6 @@ export function Layout({ children, userRole, userName }: {
|
|||||||
{n.label}
|
{n.label}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{/* Verwaltung-Dropdown (HR/Admin) */}
|
|
||||||
{visibleMgmt.length > 0 && (
|
|
||||||
<div ref={mgmtRef} className='relative'>
|
|
||||||
<button
|
|
||||||
onClick={() => setMgmtOpen(o => !o)}
|
|
||||||
className={`flex items-center gap-1 px-3 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap ${
|
|
||||||
isMgmtActive || mgmtOpen
|
|
||||||
? 'bg-blue-50 text-blue-700'
|
|
||||||
: 'text-gray-600 hover:bg-gray-100 hover:text-gray-800'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
Verwaltung
|
|
||||||
<svg className={`w-3.5 h-3.5 transition-transform ${mgmtOpen ? 'rotate-180' : ''}`}
|
|
||||||
fill='none' viewBox='0 0 24 24' stroke='currentColor'>
|
|
||||||
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth={2} d='M19 9l-7 7-7-7' />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{mgmtOpen && (
|
|
||||||
<div className='absolute left-0 top-full mt-1.5 w-56 bg-white rounded-xl shadow-lg border border-gray-200 py-1.5 z-50'>
|
|
||||||
{visibleMgmt.map(n => (
|
|
||||||
<Link
|
|
||||||
key={n.path}
|
|
||||||
to={n.path}
|
|
||||||
className={`flex items-center px-4 py-2 text-sm transition-colors ${
|
|
||||||
pathname === n.path
|
|
||||||
? 'bg-blue-50 text-blue-700 font-medium'
|
|
||||||
: 'text-gray-700 hover:bg-gray-50'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{n.label}
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{/* Rechte Seite: Health-Badge + Einstellungen + User + Abmelden */}
|
{/* Rechte Seite: Health-Badge + Einstellungen + User + Abmelden */}
|
||||||
|
|||||||
@@ -20,15 +20,7 @@ export const PRIMARY_NAV: NavItem[] = [
|
|||||||
{ path: '/time', label: 'Zeiterfassung' },
|
{ path: '/time', label: 'Zeiterfassung' },
|
||||||
{ path: '/absences', label: 'Abwesenheiten' },
|
{ path: '/absences', label: 'Abwesenheiten' },
|
||||||
{ path: '/calendar', label: 'Kalender' },
|
{ path: '/calendar', label: 'Kalender' },
|
||||||
]
|
{ path: '/reports', label: 'Berichte', roles: HR_PLUS },
|
||||||
|
|
||||||
// HR/Admin-Funktionen – gebündelt im "Verwaltung"-Dropdown
|
|
||||||
export const MANAGEMENT_NAV: NavItem[] = [
|
|
||||||
{ path: '/reports', label: 'Berichte', roles: HR_PLUS },
|
|
||||||
{ path: '/users', label: 'Mitarbeiter', roles: HR_ADMIN },
|
|
||||||
{ path: '/hr/special-assignments', label: 'Sondervertretungen', roles: HR_PLUS },
|
|
||||||
{ path: '/hr/payouts', label: 'Stunden-Auszahlung', roles: HR_ADMIN },
|
|
||||||
{ path: '/admin/tenants', label: 'Mandanten', roles: ['SUPER_ADMIN'] },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
export interface SettingsGroup {
|
export interface SettingsGroup {
|
||||||
@@ -36,8 +28,17 @@ export interface SettingsGroup {
|
|||||||
items: NavItem[]
|
items: NavItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Einstellungs-Seite (/settings): nach Kategorien gruppierte Kacheln
|
// Einstellungs-Seite (/settings): nach Kategorien gruppierte Kacheln.
|
||||||
|
// Enthält auch die HR/Admin-Verwaltung (Personal, Mandant).
|
||||||
export const SETTINGS_GROUPS: SettingsGroup[] = [
|
export const SETTINGS_GROUPS: SettingsGroup[] = [
|
||||||
|
{
|
||||||
|
title: 'Personal',
|
||||||
|
items: [
|
||||||
|
{ path: '/users', label: 'Mitarbeiter', roles: HR_ADMIN, description: 'Mitarbeiter anlegen & bearbeiten' },
|
||||||
|
{ path: '/hr/special-assignments', label: 'Sondervertretungen', roles: HR_PLUS, description: 'Sondervertretungen verwalten' },
|
||||||
|
{ path: '/hr/payouts', label: 'Stunden-Auszahlung', roles: HR_ADMIN, description: 'Überstunden auszahlen' },
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Stammdaten',
|
title: 'Stammdaten',
|
||||||
items: [
|
items: [
|
||||||
@@ -68,6 +69,12 @@ export const SETTINGS_GROUPS: SettingsGroup[] = [
|
|||||||
{ path: '/settings/smtp', label: 'SMTP', roles: ADMIN, description: 'E-Mail-Versand konfigurieren' },
|
{ path: '/settings/smtp', label: 'SMTP', roles: ADMIN, description: 'E-Mail-Versand konfigurieren' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Mandant',
|
||||||
|
items: [
|
||||||
|
{ path: '/admin/tenants', label: 'Mandanten', roles: ['SUPER_ADMIN'], description: 'Firmen & Reseller verwalten' },
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'System',
|
title: 'System',
|
||||||
items: [
|
items: [
|
||||||
|
|||||||
Reference in New Issue
Block a user