'use client' import React, { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' import { useSDK } from '@/lib/sdk' import type { ProjectInfo, CustomerType } from '@/lib/sdk/types' // ============================================================================= // HELPERS // ============================================================================= /** Map snake_case backend response to camelCase ProjectInfo */ function normalizeProject(p: any): ProjectInfo { return { id: p.id, name: p.name, description: p.description || '', customerType: p.customerType || p.customer_type || 'new', status: p.status || 'active', projectVersion: p.projectVersion ?? p.project_version ?? 1, completionPercentage: p.completionPercentage ?? p.completion_percentage ?? 0, createdAt: p.createdAt || p.created_at || '', updatedAt: p.updatedAt || p.updated_at || '', } } function formatTimeAgo(dateStr: string): string { if (!dateStr) return '' const date = new Date(dateStr) if (isNaN(date.getTime())) return '' 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' : ''}` } // ============================================================================= // CREATE PROJECT DIALOG // ============================================================================= interface CreateProjectDialogProps { open: boolean onClose: () => void onCreated: (project: ProjectInfo) => void existingProjects: ProjectInfo[] } function CreateProjectDialog({ open, onClose, onCreated, existingProjects }: CreateProjectDialogProps) { const { createProject } = useSDK() const [name, setName] = useState('') const [customerType, setCustomerType] = useState('new') const [copyFromId, setCopyFromId] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) const [error, setError] = useState('') if (!open) return null const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!name.trim()) { setError('Projektname ist erforderlich') return } setIsSubmitting(true) setError('') try { const project = await createProject( name.trim(), customerType, copyFromId || undefined ) onCreated(normalizeProject(project)) setName('') setCopyFromId('') onClose() } catch (err) { setError(err instanceof Error ? err.message : 'Fehler beim Erstellen des Projekts') } finally { setIsSubmitting(false) } } return (
e.stopPropagation()} >

Neues Projekt erstellen

{/* Project Name */}
setName(e.target.value)} placeholder="z.B. KI-Produkt X, SaaS API, Tochter GmbH..." className="w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 outline-none" autoFocus />
{/* Customer Type */}
{/* Copy from existing project */} {existingProjects.length > 0 && (

Firmenprofil wird kopiert und kann dann unabhaengig bearbeitet werden.

)} {/* Error */} {error && (
{error}
)} {/* Actions */}
) } // ============================================================================= // PROJECT ACTION DIALOG (Archive / Permanent Delete) // ============================================================================= type ActionStep = 'choose' | 'confirm-delete' function ProjectActionDialog({ project, onArchive, onPermanentDelete, onCancel, isProcessing, }: { project: ProjectInfo onArchive: () => void onPermanentDelete: () => void onCancel: () => void isProcessing: boolean }) { const [step, setStep] = useState('choose') if (step === 'confirm-delete') { return (
e.stopPropagation()} >

Endgueltig loeschen

Sind Sie sicher, dass Sie {project.name} unwiderruflich loeschen moechten?

Alle Projektdaten, SDK-States und Dokumente werden permanent geloescht. Diese Aktion kann nicht rueckgaengig gemacht werden.

) } return (
e.stopPropagation()} >

Projekt entfernen

Was moechten Sie mit dem Projekt {project.name} tun?

{/* Archive option */} {/* Permanent delete option */}
) } // ============================================================================= // PROJECT CARD // ============================================================================= function ProjectCard({ project, onClick, onDelete, onRestore, }: { project: ProjectInfo onClick: () => void onDelete?: () => void onRestore?: () => void }) { const timeAgo = formatTimeAgo(project.updatedAt) const isArchived = project.status === 'archived' return (
{/* Action buttons */}
{isArchived && onRestore && ( )} {onDelete && ( )}
{/* Card content */}
) } // ============================================================================= // MAIN COMPONENT // ============================================================================= export function ProjectSelector() { const router = useRouter() const { listProjects, archiveProject, restoreProject, permanentlyDeleteProject } = useSDK() const [projects, setProjects] = useState([]) const [archivedProjects, setArchivedProjects] = useState([]) const [loading, setLoading] = useState(true) const [showCreateDialog, setShowCreateDialog] = useState(false) const [actionTarget, setActionTarget] = useState(null) const [isProcessing, setIsProcessing] = useState(false) const [showArchived, setShowArchived] = useState(false) useEffect(() => { loadProjects() }, []) const loadProjects = async () => { setLoading(true) try { const result = await listProjects() const all = result.map(normalizeProject) setProjects(all.filter(p => p.status === 'active')) setArchivedProjects(all.filter(p => p.status === 'archived')) } catch (error) { console.error('Failed to load projects:', error) } finally { setLoading(false) } } const handleProjectClick = (project: ProjectInfo) => { router.push(`/sdk?project=${project.id}`) } const handleProjectCreated = (project: ProjectInfo) => { router.push(`/sdk?project=${project.id}`) } const handleArchive = async () => { if (!actionTarget) return setIsProcessing(true) try { await archiveProject(actionTarget.id) // Move from active to archived setProjects(prev => prev.filter(p => p.id !== actionTarget.id)) setArchivedProjects(prev => [...prev, { ...actionTarget, status: 'archived' as const }]) setActionTarget(null) } catch (error) { console.error('Failed to archive project:', error) } finally { setIsProcessing(false) } } const handlePermanentDelete = async () => { if (!actionTarget) return setIsProcessing(true) try { await permanentlyDeleteProject(actionTarget.id) setProjects(prev => prev.filter(p => p.id !== actionTarget.id)) setArchivedProjects(prev => prev.filter(p => p.id !== actionTarget.id)) setActionTarget(null) } catch (error) { console.error('Failed to delete project:', error) } finally { setIsProcessing(false) } } const handleRestore = async (project: ProjectInfo) => { try { await restoreProject(project.id) setArchivedProjects(prev => prev.filter(p => p.id !== project.id)) setProjects(prev => [...prev, { ...project, status: 'active' as const }]) } catch (error) { console.error('Failed to restore project:', error) } } return (
{/* Header */}

Ihre Projekte

Waehlen Sie ein Compliance-Projekt oder erstellen Sie ein neues.

{/* Loading */} {loading && (
)} {/* Empty State */} {!loading && projects.length === 0 && archivedProjects.length === 0 && (

Noch keine Projekte

Erstellen Sie Ihr erstes Compliance-Projekt, um mit der DSGVO- und AI-Act-Konformitaet zu beginnen.

)} {/* Active Projects */} {!loading && projects.length > 0 && (
{projects.map(project => ( handleProjectClick(project)} onDelete={() => setActionTarget(project)} /> ))}
)} {/* Archived Projects Section */} {!loading && archivedProjects.length > 0 && (
{showArchived && (
{archivedProjects.map(project => ( handleProjectClick(project)} onRestore={() => handleRestore(project)} onDelete={() => setActionTarget(project)} /> ))}
)}
)} {/* Create Dialog */} setShowCreateDialog(false)} onCreated={handleProjectCreated} existingProjects={projects} /> {/* Action Dialog (Archive / Delete) */} {actionTarget && ( setActionTarget(null)} isProcessing={isProcessing} /> )}
) }