This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/app/(sdk)/layout.tsx
BreakPilot Dev 660295e218 fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit
restores all missing components:

- Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education,
  infrastructure, communication, development, onboarding, rbac
- SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen,
  vendor-compliance, tom-generator, dsr, and more
- Developer portal (25 pages): API docs, SDK guides, frameworks
- All components, lib files, hooks, and types
- Updated package.json with all dependencies

The issue was caused by incomplete initial repository state - the full
admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2
but was never fully synced to the main admin-v2 directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 23:40:15 -08:00

166 lines
5.8 KiB
TypeScript

'use client'
import { useEffect, useState } from 'react'
import { useRouter } 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 { useSDK } from '@/lib/sdk'
import { getStoredRole } from '@/lib/roles'
// =============================================================================
// SDK HEADER
// =============================================================================
function SDKHeader({ sidebarCollapsed }: { sidebarCollapsed: boolean }) {
const { currentStep, setCommandBarOpen, completionPercentage } = useSDK()
return (
<header className="sticky top-0 z-30 bg-white border-b border-gray-200">
<div className="flex items-center justify-between px-6 py-3">
{/* Breadcrumb / Current Step */}
<div className="flex items-center gap-3">
<nav className="flex items-center text-sm text-gray-500">
<span>SDK</span>
<svg className="w-4 h-4 mx-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
<span className="text-gray-900 font-medium">
{currentStep?.name || 'Dashboard'}
</span>
</nav>
</div>
{/* Actions */}
<div className="flex items-center gap-4">
{/* Command Bar Trigger */}
<button
onClick={() => setCommandBarOpen(true)}
className="flex items-center gap-2 px-3 py-1.5 text-sm text-gray-500 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<span>Suchen...</span>
<kbd className="ml-2 px-1.5 py-0.5 text-xs bg-gray-200 rounded">K</kbd>
</button>
{/* Progress Indicator */}
<div className="flex items-center gap-2">
<div className="w-24 h-2 bg-gray-200 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-purple-500 to-indigo-500 rounded-full transition-all duration-500"
style={{ width: `${completionPercentage}%` }}
/>
</div>
<span className="text-sm font-medium text-gray-600">{completionPercentage}%</span>
</div>
{/* Help Button */}
<button className="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</button>
</div>
</div>
</header>
)
}
// =============================================================================
// INNER LAYOUT (needs SDK context)
// =============================================================================
function SDKInnerLayout({ children }: { children: React.ReactNode }) {
const { isCommandBarOpen, setCommandBarOpen } = useSDK()
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
// 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 (
<div className="min-h-screen bg-gray-50">
{/* Sidebar */}
<SDKSidebar
collapsed={sidebarCollapsed}
onCollapsedChange={handleCollapsedChange}
/>
{/* Main Content - dynamic margin based on sidebar state */}
<div className={`${sidebarCollapsed ? 'ml-16' : 'ml-64'} flex flex-col min-h-screen transition-all duration-300`}>
{/* Header */}
<SDKHeader sidebarCollapsed={sidebarCollapsed} />
{/* Page Content */}
<main className="flex-1 p-6">{children}</main>
</div>
{/* Command Bar Modal */}
{isCommandBarOpen && <CommandBar onClose={() => setCommandBarOpen(false)} />}
{/* Pipeline Sidebar (FAB on mobile/tablet, fixed on desktop xl+) */}
<SDKPipelineSidebar />
</div>
)
}
// =============================================================================
// MAIN LAYOUT
// =============================================================================
export default function SDKRootLayout({
children,
}: {
children: React.ReactNode
}) {
const router = useRouter()
const [loading, setLoading] = useState(true)
useEffect(() => {
// Check if role is stored (auth check)
const role = getStoredRole()
if (!role) {
router.replace('/')
} else {
setLoading(false)
}
}, [router])
if (loading) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-purple-600"></div>
</div>
)
}
return (
<SDKProvider>
<SDKInnerLayout>{children}</SDKInnerLayout>
</SDKProvider>
)
}