'use client' import React from 'react' import Link from 'next/link' import { usePathname } from 'next/navigation' import { useSDK, SDK_STEPS, SDK_PACKAGES, getStepsForPackage, type SDKPackageId, type SDKStep, } from '@/lib/sdk' import { CollapseIcon } from './SidebarIcons' import { ProgressBar, PackageIndicator, StepItem, CorpusStalenessInfo, withProject, } from './SidebarSubComponents' import { SidebarModuleList } from './SidebarModuleList' // ============================================================================= // MAIN SIDEBAR // ============================================================================= interface SDKSidebarProps { collapsed?: boolean onCollapsedChange?: (collapsed: boolean) => void } export function SDKSidebar({ collapsed = false, onCollapsedChange }: SDKSidebarProps) { const pathname = usePathname() const { state, packageCompletion, completionPercentage, getCheckpointStatus, projectId } = useSDK() const [pendingCRCount, setPendingCRCount] = React.useState(0) // Poll pending change-request count every 60s React.useEffect(() => { let active = true async function fetchCRCount() { try { const res = await fetch('/api/sdk/v1/compliance/change-requests/stats') if (res.ok) { const data = await res.json() if (active) setPendingCRCount(data.total_pending || 0) } } catch { /* ignore */ } } fetchCRCount() const interval = setInterval(fetchCRCount, 60000) return () => { active = false; clearInterval(interval) } }, []) const [expandedPackages, setExpandedPackages] = React.useState>({ 'vorbereitung': true, 'analyse': false, 'dokumentation': false, 'rechtliche-texte': false, 'betrieb': false, }) // Auto-expand current package React.useEffect(() => { const currentStep = SDK_STEPS.find(s => s.url === pathname) if (currentStep) { setExpandedPackages(prev => ({ ...prev, [currentStep.package]: true, })) } }, [pathname]) const togglePackage = (packageId: SDKPackageId) => { setExpandedPackages(prev => ({ ...prev, [packageId]: !prev[packageId] })) } const isStepLocked = (step: SDKStep): boolean => { if (state.preferences?.allowParallelWork) return false return step.prerequisiteSteps.some(prereq => !state.completedSteps.includes(prereq)) } const isPackageLocked = (packageId: SDKPackageId): boolean => { if (state.preferences?.allowParallelWork) return false const pkg = SDK_PACKAGES.find(p => p.id === packageId) if (!pkg || pkg.order === 1) return false const prevPkg = SDK_PACKAGES.find(p => p.order === pkg.order - 1) if (!prevPkg) return false return packageCompletion[prevPkg.id] < 100 } const getStepCheckpointStatus = (step: SDKStep): 'passed' | 'failed' | 'warning' | 'pending' => { const status = getCheckpointStatus(step.checkpointId) if (!status) return 'pending' if (status.passed) return 'passed' if (status.errors.length > 0) return 'failed' if (status.warnings.length > 0) return 'warning' return 'pending' } const isStepActive = (stepUrl: string) => pathname === stepUrl const isPackageActive = (packageId: SDKPackageId) => { const steps = getStepsForPackage(packageId) return steps.some(s => s.url === pathname) } const getVisibleStepsForPackage = (packageId: SDKPackageId): SDKStep[] => { const steps = getStepsForPackage(packageId) return steps.filter(step => { if (step.visibleWhen) return step.visibleWhen(state) return true }) } return ( ) }