Kairo-Jinkendo/frontend/src/components/FieldRenderer.jsx
Lars a6fc86025c
All checks were successful
Deploy Development / deploy (push) Successful in 44s
Test Suite / pytest-backend (push) Successful in 1m54s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 19s
Test Suite / playwright-smoke (push) Successful in 15s
AP1.10b/10c: Entity Field System mit dynamischen Vorhaben-Zusatzfeldern.
EFS-Tabellen, Registry-Sync und Fields-API ermöglichen archetyp-spezifische Felder; Frontend rendert sie im Profil-Modal per FieldRenderer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 13:53:07 +02:00

105 lines
2.6 KiB
JavaScript

export function FieldRenderer({ definitions, values, onChange, disabled = false }) {
if (!definitions?.length) {
return null
}
return (
<fieldset className="field-renderer">
<legend className="field-renderer__legend">Zusatzfelder</legend>
{definitions.map((def) => (
<DynamicField
key={def.field_key}
definition={def}
value={values?.[def.field_key]}
onChange={(next) => onChange(def.field_key, next)}
disabled={disabled}
/>
))}
</fieldset>
)
}
function DynamicField({ definition, value, onChange, disabled }) {
const { field_key, field_type, label, required, validation_json: validation } = definition
const inputId = `field-${field_key}`
if (field_type === 'longtext') {
return (
<label htmlFor={inputId}>
{label}
{required && ' *'}
<textarea
id={inputId}
name={field_key}
rows={4}
value={value ?? ''}
onChange={(e) => onChange(e.target.value)}
required={required}
disabled={disabled}
/>
</label>
)
}
if (field_type === 'boolean') {
return (
<label className="checkbox-label" htmlFor={inputId}>
<input
id={inputId}
name={field_key}
type="checkbox"
checked={Boolean(value)}
onChange={(e) => onChange(e.target.checked)}
disabled={disabled}
/>
{label}
{required && ' *'}
</label>
)
}
if (field_type === 'enum') {
const options = validation?.options || []
return (
<label htmlFor={inputId}>
{label}
{required && ' *'}
<select
id={inputId}
name={field_key}
value={value ?? ''}
onChange={(e) => onChange(e.target.value)}
required={required}
disabled={disabled}
>
<option value="">—</option>
{options.map((opt) => (
<option key={opt} value={opt}>
{opt}
</option>
))}
</select>
</label>
)
}
const inputType =
field_type === 'number' ? 'number' : field_type === 'date' ? 'date' : field_type === 'url' ? 'url' : 'text'
return (
<label htmlFor={inputId}>
{label}
{required && ' *'}
<input
id={inputId}
name={field_key}
type={inputType}
value={value ?? ''}
onChange={(e) => onChange(field_type === 'number' ? e.target.value : e.target.value)}
required={required}
disabled={disabled}
/>
</label>
)
}