'use client' import { useEffect, useState } from 'react' import { usePathname, useSearchParams } from 'next/navigation' import { SDKProvider } from '@/lib/sdk' import { SDKSidebar } from '@/components/sdk/Sidebar/SDKSidebar' import { CommandBar } from '@/components/sdk/CommandBar' import { SDKPipelineSidebar } from '@/components/sdk/SDKPipelineSidebar' import { ComplianceAdvisorWidget } from '@/components/sdk/ComplianceAdvisorWidget' import { useSDK } from '@/lib/sdk' // ============================================================================= // SDK HEADER // ============================================================================= function formatTimeAgo(date: Date | null): string { if (!date) return 'Nie' const now = Date.now() const diff = now - date.getTime() const seconds = Math.floor(diff / 1000) if (seconds < 60) return 'Gerade eben' const minutes = Math.floor(seconds / 60) if (minutes < 60) return `vor ${minutes} Min` const hours = Math.floor(minutes / 60) if (hours < 24) return `vor ${hours} Std` const days = Math.floor(hours / 24) return `vor ${days} Tag${days > 1 ? 'en' : ''}` } const SYNC_STATUS_CONFIG = { idle: { color: 'bg-green-400', label: 'Sync OK' }, syncing: { color: 'bg-yellow-400 animate-pulse', label: 'Synchronisiere...' }, error: { color: 'bg-red-400', label: 'Sync-Fehler' }, conflict: { color: 'bg-orange-400', label: 'Konflikt' }, offline: { color: 'bg-gray-400', label: 'Offline' }, } as const function SDKHeader({ sidebarCollapsed }: { sidebarCollapsed: boolean }) { const { state, currentStep, setCommandBarOpen, completionPercentage, syncState, projectId } = useSDK() const syncConfig = SYNC_STATUS_CONFIG[syncState.status] || SYNC_STATUS_CONFIG.idle return (
{/* Breadcrumb / Current Step */}
{/* Actions */}
{/* Command Bar Trigger */} {/* Progress Indicator */}
{completionPercentage}%
{/* Help Button */}
{/* Session Info Bar */}
{/* Projekt-Name */} {state.projectInfo?.name || state.companyProfile?.companyName || 'Kein Projekt'} {/* Firmenname (falls abweichend vom Projektnamen) */} {state.projectInfo && state.companyProfile?.companyName && state.companyProfile.companyName !== state.projectInfo.name && ( <> | {state.companyProfile.companyName} )} V{String(state.projectVersion || 1).padStart(3, '0')} | {/* Current step / last activity */} Zuletzt: {currentStep?.name || 'Dashboard'} | {/* Last saved time */} {formatTimeAgo(syncState.lastSyncedAt ? new Date(syncState.lastSyncedAt) : state.lastModified ? new Date(state.lastModified) : null)} | {/* Sync status dot */} {syncConfig.label} {/* User (only if not default) */} {state.userId && state.userId !== 'default' && ( <> | Bearbeiter: {state.userId} )}
) } // ============================================================================= // INNER LAYOUT (needs SDK context) // ============================================================================= function SDKInnerLayout({ children }: { children: React.ReactNode }) { const { isCommandBarOpen, setCommandBarOpen, projectId } = useSDK() const [sidebarCollapsed, setSidebarCollapsed] = useState(false) const pathname = usePathname() // Extract current step from pathname (e.g., /sdk/vvt -> vvt) const currentStep = pathname?.split('/').pop() || 'default' // Load collapsed state from localStorage useEffect(() => { const stored = localStorage.getItem('sdk-sidebar-collapsed') if (stored !== null) { setSidebarCollapsed(stored === 'true') } }, []) // Save collapsed state to localStorage const handleCollapsedChange = (collapsed: boolean) => { setSidebarCollapsed(collapsed) localStorage.setItem('sdk-sidebar-collapsed', String(collapsed)) } return (
{/* Sidebar — always visible */} {/* Main Content - dynamic margin based on sidebar state */}
{/* Header — always visible */} {/* Page Content */}
{children}
{/* Command Bar Modal */} {isCommandBarOpen && setCommandBarOpen(false)} />} {/* Pipeline Sidebar (FAB on mobile/tablet, fixed on desktop xl+) */} {projectId && } {/* Compliance Advisor Widget */} {projectId && }
) } // ============================================================================= // SDK ROOT WITH SEARCH PARAMS (client component that reads ?project=) // ============================================================================= import { Suspense } from 'react' function SDKRootWithParams({ children }: { children: React.ReactNode }) { const searchParams = useSearchParams() const projectId = searchParams.get('project') || undefined return ( {children} ) } // ============================================================================= // MAIN LAYOUT (wraps in Suspense for useSearchParams) // ============================================================================= export default function SDKRootLayout({ children, }: { children: React.ReactNode }) { return ( }> {children} ) }