'use client' import { useState, useEffect, useCallback } from 'react' import { X } from 'lucide-react' import type { CatalogMeta, CatalogEntry, CatalogFieldSchema, } from '@/lib/sdk/catalog-manager/types' interface CatalogEntryFormProps { catalog: CatalogMeta entry?: CatalogEntry | null onSave: (data: Record) => void onCancel: () => void } export default function CatalogEntryForm({ catalog, entry, onSave, onCancel, }: CatalogEntryFormProps) { const isEditMode = entry !== null && entry !== undefined const isSystemEntry = isEditMode && entry?.source === 'system' const isCreateMode = !isEditMode const title = isSystemEntry ? 'Details' : isEditMode ? 'Eintrag bearbeiten' : 'Neuer Eintrag' const [formData, setFormData] = useState>({}) const [errors, setErrors] = useState>({}) // Initialize form data useEffect(() => { if (isEditMode && entry) { const initialData: Record = {} for (const field of catalog.fields) { initialData[field.key] = entry.data?.[field.key] ?? getDefaultValue(field) } setFormData(initialData) } else { const initialData: Record = {} for (const field of catalog.fields) { initialData[field.key] = getDefaultValue(field) } setFormData(initialData) } }, [entry, catalog.fields, isEditMode]) function getDefaultValue(field: CatalogFieldSchema): unknown { switch (field.type) { case 'text': case 'textarea': return '' case 'number': return field.min ?? 0 case 'select': return '' case 'multiselect': return [] case 'boolean': return false case 'tags': return '' default: return '' } } const handleFieldChange = useCallback( (key: string, value: unknown) => { setFormData(prev => ({ ...prev, [key]: value })) // Clear error on change if (errors[key]) { setErrors(prev => { const next = { ...prev } delete next[key] return next }) } }, [errors] ) const handleMultiselectToggle = useCallback( (key: string, option: string) => { setFormData(prev => { const current = (prev[key] as string[]) || [] const updated = current.includes(option) ? current.filter(v => v !== option) : [...current, option] return { ...prev, [key]: updated } }) }, [] ) const validate = (): boolean => { const newErrors: Record = {} for (const field of catalog.fields) { if (field.required) { const value = formData[field.key] if (value === undefined || value === null || value === '') { newErrors[field.key] = `${field.label} ist ein Pflichtfeld` } else if (Array.isArray(value) && value.length === 0) { newErrors[field.key] = `Mindestens ein Wert erforderlich` } } } setErrors(newErrors) return Object.keys(newErrors).length === 0 } const handleSubmit = (e: React.FormEvent) => { e.preventDefault() if (isSystemEntry) return if (validate()) { // Convert tags string to array before saving const processedData = { ...formData } for (const field of catalog.fields) { if (field.type === 'tags' && typeof processedData[field.key] === 'string') { processedData[field.key] = (processedData[field.key] as string) .split(',') .map(t => t.trim()) .filter(Boolean) } } onSave(processedData) } } // Close on Escape key useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') onCancel() } window.addEventListener('keydown', handleKeyDown) return () => window.removeEventListener('keydown', handleKeyDown) }, [onCancel]) const renderField = (field: CatalogFieldSchema) => { const value = formData[field.key] const hasError = !!errors[field.key] const isDisabled = isSystemEntry const baseInputClasses = `w-full px-3 py-2 text-sm border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent transition-colors ${ hasError ? 'border-red-400 dark:border-red-500' : 'border-gray-300 dark:border-gray-600' } ${isDisabled ? 'opacity-60 cursor-not-allowed bg-gray-50 dark:bg-gray-800' : ''}` switch (field.type) { case 'text': return ( handleFieldChange(field.key, e.target.value)} placeholder={field.placeholder || ''} disabled={isDisabled} className={baseInputClasses} /> ) case 'textarea': return (