All 4 page.tsx files reduced well below 500 LOC (235/181/158/262) by extracting components and hooks into colocated _components/ and _hooks/ subdirectories. Zero behavior changes — logic relocated verbatim. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
159 lines
6.5 KiB
TypeScript
159 lines
6.5 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { useParams } from 'next/navigation'
|
|
import { Component } from './_components/types'
|
|
import { ComponentTreeNode } from './_components/ComponentTreeNode'
|
|
import { ComponentForm } from './_components/ComponentForm'
|
|
import { ComponentLibraryModal } from './_components/ComponentLibraryModal'
|
|
import { useComponents } from './_hooks/useComponents'
|
|
|
|
export default function ComponentsPage() {
|
|
const params = useParams()
|
|
const projectId = params.projectId as string
|
|
|
|
const { loading, tree, handleSubmit, handleDelete, handleAddFromLibrary } = useComponents(projectId)
|
|
|
|
const [showForm, setShowForm] = useState(false)
|
|
const [editingComponent, setEditingComponent] = useState<Component | null>(null)
|
|
const [addingParentId, setAddingParentId] = useState<string | null>(null)
|
|
const [showLibrary, setShowLibrary] = useState(false)
|
|
|
|
function handleEdit(component: Component) {
|
|
setEditingComponent(component)
|
|
setAddingParentId(null)
|
|
setShowForm(true)
|
|
}
|
|
|
|
function handleAddChild(parentId: string) {
|
|
setAddingParentId(parentId)
|
|
setEditingComponent(null)
|
|
setShowForm(true)
|
|
}
|
|
|
|
function resetForm() {
|
|
setShowForm(false)
|
|
setEditingComponent(null)
|
|
setAddingParentId(null)
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="flex items-center justify-center h-64">
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">Komponenten</h1>
|
|
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
|
Erfassen Sie alle Software-, Firmware-, KI- und Hardware-Komponenten der Maschine.
|
|
</p>
|
|
</div>
|
|
{!showForm && (
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={() => setShowLibrary(true)}
|
|
className="flex items-center gap-2 px-3 py-2 border border-purple-300 text-purple-700 rounded-lg hover:bg-purple-50 transition-colors text-sm"
|
|
>
|
|
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
|
|
</svg>
|
|
Aus Bibliothek waehlen
|
|
</button>
|
|
<button
|
|
onClick={() => { setShowForm(true); setEditingComponent(null); setAddingParentId(null) }}
|
|
className="flex items-center gap-2 px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 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="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
|
</svg>
|
|
Komponente hinzufuegen
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{showLibrary && (
|
|
<ComponentLibraryModal
|
|
onAdd={async (comps, energy) => { setShowLibrary(false); await handleAddFromLibrary(comps, energy) }}
|
|
onClose={() => setShowLibrary(false)}
|
|
/>
|
|
)}
|
|
|
|
{showForm && (
|
|
<ComponentForm
|
|
onSubmit={async (data) => {
|
|
const ok = await handleSubmit(data, editingComponent?.id)
|
|
if (ok) resetForm()
|
|
}}
|
|
onCancel={resetForm}
|
|
initialData={editingComponent}
|
|
parentId={addingParentId}
|
|
/>
|
|
)}
|
|
|
|
{/* Component Tree */}
|
|
{tree.length > 0 ? (
|
|
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 divide-y divide-gray-100 dark:divide-gray-700">
|
|
<div className="px-4 py-3 bg-gray-50 dark:bg-gray-750 rounded-t-xl">
|
|
<div className="flex items-center gap-2 text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
<span className="w-5" />
|
|
<span>Typ</span>
|
|
<span className="flex-1">Name</span>
|
|
<span className="hidden lg:block w-[200px]">Beschreibung</span>
|
|
<span className="w-24">Aktionen</span>
|
|
</div>
|
|
</div>
|
|
<div className="py-1">
|
|
{tree.map((component) => (
|
|
<ComponentTreeNode
|
|
key={component.id}
|
|
component={component}
|
|
depth={0}
|
|
onEdit={handleEdit}
|
|
onDelete={handleDelete}
|
|
onAddChild={handleAddChild}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
!showForm && (
|
|
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-12 text-center">
|
|
<div className="w-16 h-16 mx-auto bg-purple-100 dark:bg-purple-900/30 rounded-full flex items-center justify-center mb-4">
|
|
<svg className="w-8 h-8 text-purple-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
|
</svg>
|
|
</div>
|
|
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Keine Komponenten erfasst</h3>
|
|
<p className="mt-2 text-gray-500 max-w-md mx-auto">
|
|
Beginnen Sie mit der Erfassung aller relevanten Komponenten Ihrer Maschine.
|
|
Erstellen Sie eine hierarchische Struktur aus Software, Firmware, KI-Modulen und Hardware.
|
|
</p>
|
|
<div className="mt-6 flex items-center justify-center gap-3">
|
|
<button
|
|
onClick={() => setShowLibrary(true)}
|
|
className="px-6 py-3 border border-purple-300 text-purple-700 rounded-lg hover:bg-purple-50 transition-colors"
|
|
>
|
|
Aus Bibliothek waehlen
|
|
</button>
|
|
<button
|
|
onClick={() => setShowForm(true)}
|
|
className="px-6 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
|
|
>
|
|
Manuell hinzufuegen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)
|
|
)}
|
|
</div>
|
|
)
|
|
}
|