'use client' import { useState, useEffect } from 'react' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { ScrollArea } from '@/components/ui/scroll-area' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' import { Plus, Save, FolderOpen, Download, Clock, Sun, Moon, Maximize, Minimize, ClipboardList, Settings, LogOut, User, MoreVertical, Trash2, AlertTriangle, List, Eraser, ImagePlus, Key, Shield, Building2, MapPin, } from 'lucide-react' import { HoseSettingsDialog } from '@/components/dialogs/hose-settings-dialog' import type { Project, DrawFeature } from '@/app/app/page' import { formatDateTime } from '@/lib/utils' import { Logo } from '@/components/ui/logo' interface TopbarProps { project: Project | null onNewProject: () => void onSaveProject: () => void onLoadProject: (project: Project, features: DrawFeature[]) => void onDeleteProject?: (projectId: string) => void onExport: (format: 'png' | 'pdf') => void onClearAll?: () => void onPlanUpload?: () => void isSaving: boolean isDarkMode: boolean onToggleTheme: () => void isFullscreen: boolean onToggleFullscreen: () => void auditLog: { time: string; action: string }[] isAuditOpen: boolean onToggleAudit: () => void userName?: string userRole?: string onLogout?: () => void } export function Topbar({ project, onNewProject, onSaveProject, onLoadProject, onDeleteProject, onExport, onClearAll, onPlanUpload, isSaving, isDarkMode, onToggleTheme, isFullscreen, onToggleFullscreen, auditLog, isAuditOpen, onToggleAudit, userName, userRole, onLogout, }: TopbarProps) { const [isLoadDialogOpen, setIsLoadDialogOpen] = useState(false) const [isHoseSettingsOpen, setIsHoseSettingsOpen] = useState(false) const [showPasswordDialog, setShowPasswordDialog] = useState(false) const [showDeleteAccountDialog, setShowDeleteAccountDialog] = useState(false) const [deleteAccountPw, setDeleteAccountPw] = useState('') const [deleteAccountLoading, setDeleteAccountLoading] = useState(false) const [deleteAccountError, setDeleteAccountError] = useState('') const [pwOld, setPwOld] = useState('') const [pwNew, setPwNew] = useState('') const [pwConfirm, setPwConfirm] = useState('') const [pwLoading, setPwLoading] = useState(false) const [pwStatus, setPwStatus] = useState<'success' | 'error' | null>(null) const [pwError, setPwError] = useState('') const [projects, setProjects] = useState([]) const [isLoadingProjects, setIsLoadingProjects] = useState(false) const [deleteConfirmId, setDeleteConfirmId] = useState(null) const [isDeleting, setIsDeleting] = useState(false) // Live clock const [now, setNow] = useState(new Date()) useEffect(() => { const timer = setInterval(() => setNow(new Date()), 1000) return () => clearInterval(timer) }, []) const handleOpenLoadDialog = async () => { setIsLoadDialogOpen(true) setIsLoadingProjects(true) try { const res = await fetch('/api/projects') if (res.ok) { const data = await res.json() setProjects(data.projects) } } catch (error) { console.error('Error loading projects:', error) } finally { setIsLoadingProjects(false) } } const handleLoadProject = async (projectId: string) => { try { const res = await fetch(`/api/projects/${projectId}`) if (res.ok) { const data = await res.json() onLoadProject(data.project, data.project.features || []) setIsLoadDialogOpen(false) } } catch (error) { console.error('Error loading project:', error) } } const handleExport = (format: 'png' | 'pdf') => { onExport(format) } return (
Lageplan v{process.env.APP_VERSION}
Neuer Einsatz Einsätze verwalten handleExport('png')} className="py-2.5 px-3"> Als PNG exportieren handleExport('pdf')} className="py-2.5 px-3"> Als PDF exportieren {onClearAll && ( Zeichnung leeren )} {(userRole === 'SERVER_ADMIN' || userRole === 'TENANT_ADMIN') && ( window.location.href = '/admin'} className="py-2.5 px-3"> Einstellungen )}
{/* Project info - desktop only */} {project && (
{(project as any).einsatzNr && ( {(project as any).einsatzNr} )} {project.title} {project.location && ( <>|{project.location} )}
)} {/* Clock - desktop only */}
{now.toLocaleTimeString('de-CH', { hour: '2-digit', minute: '2-digit' })}
{/* Desktop: individual buttons */} {/* Desktop: User menu dropdown */} {userName && onLogout && (

{userName}

{userRole &&

{userRole}

}
setShowPasswordDialog(true)}> Kennwort ändern {userRole === 'TENANT_ADMIN' && ( window.location.href = '/settings'}> Organisation )} {(userRole === 'SERVER_ADMIN' || userRole === 'TENANT_ADMIN') && ( window.location.href = '/admin'}> Administration )} { setShowDeleteAccountDialog(true); setDeleteAccountPw(''); setDeleteAccountError('') }} className="text-destructive focus:text-destructive" > Konto löschen Abmelden
)} {/* Mobile: overflow menu with all secondary actions */} {isDarkMode ? : } {isDarkMode ? 'Tagmodus' : 'Nachtmodus'} {isFullscreen ? : } {isFullscreen ? 'Vollbild verlassen' : 'Vollbild'} setIsHoseSettingsOpen(true)}> Einstellungen Audit Trail {auditLog.length > 0 && `(${auditLog.length})`} {onLogout && ( Abmelden {userName && `(${userName})`} )}
{/* Audit Trail Panel */} {isAuditOpen && (
Audit Trail
{auditLog.length === 0 ? (

Noch keine Aktionen

) : ( auditLog.map((entry, i) => (
{entry.time} {entry.action}
)) )}
)} {/* Project Management Dialog */} Einsätze verwalten {isLoadingProjects ? (
Laden...
) : projects.length === 0 ? (
Keine Einsätze vorhanden
) : (
{projects.map((p) => (
))}
)}
{/* Delete Confirmation Dialog */} setDeleteConfirmId(null)}> Einsatz löschen?

Dieser Einsatz wird unwiderruflich gelöscht, inklusive aller Zeichnungen, Journal-Einträge und Daten.

{/* Password Change Dialog */} { setShowPasswordDialog(open) if (!open) { setPwOld(''); setPwNew(''); setPwConfirm(''); setPwStatus(null); setPwError('') } }}> Kennwort ändern
setPwOld(e.target.value)} className="w-full border rounded-md px-3 py-2 text-sm mt-1" autoComplete="current-password" />
setPwNew(e.target.value)} className="w-full border rounded-md px-3 py-2 text-sm mt-1" autoComplete="new-password" />
setPwConfirm(e.target.value)} className="w-full border rounded-md px-3 py-2 text-sm mt-1" autoComplete="new-password" />
{pwStatus === 'error' &&

{pwError}

} {pwStatus === 'success' &&

Kennwort erfolgreich geändert!

}
{/* Delete Account Dialog */} Konto löschen

Ihr Konto wird unwiderruflich gelöscht. Ihre Projekte und Daten bleiben der Organisation erhalten, aber Ihr persönlicher Zugang wird entfernt.

{userRole === 'TENANT_ADMIN' && (
Hinweis: Als einziger Administrator müssen Sie zuerst die Organisation unter Einstellungen löschen oder die Admin-Rolle übertragen.
)}
{ setDeleteAccountPw(e.target.value); setDeleteAccountError('') }} placeholder="Ihr Passwort" className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm" autoComplete="current-password" />
{deleteAccountError && (

{deleteAccountError}

)}
) }