/** * EXHIBITION: Ausstellungen-Tab — Show-/Ausstellungsergebnisse & Auszeichnungen * eines Tieres (RennmausPro `ausz_tb`). Liste (neueste zuerst) + Inline-Formular * zum Anlegen/Bearbeiten, Löschen mit Bestätigung. Deutsch durchgehend (de.ts). * * Eigenständige Komponente mit nur EINER Einbindungs-Zeile in GerbilDetailPage * (entkoppelt: loses gerbilId ohne FK, übersteht den Import-Wipe). */ import { useState, type FormEvent } from 'react' import { de } from '../strings/de' import { createExhibitionResult, deleteExhibitionResult, listExhibitionResults, updateExhibitionResult, type CreateExhibitionResult, type ExhibitionResult, } from '../api/exhibitions' import { useApi, useMutation } from '../hooks/useApi' import { formatDate } from '../format/labels' interface FormState { eventName: string date: string placement: string award: string note: string } const emptyForm = (): FormState => ({ eventName: '', date: '', placement: '', award: '', note: '', }) /** A stored date-time → the date input's "yyyy-MM-dd" value (empty if none). */ function toDateInput(value: string | null): string { if (!value) return '' return value.slice(0, 10) } export default function GerbilExhibitionsTab({ gerbilId, entityName, }: { gerbilId: string entityName: string }) { const t = de.pages.tierTabs.exhibitions const ta = de.pages.tierTabs.actions const records = useApi(() => listExhibitionResults(gerbilId), [gerbilId]) // editing: null = kein Formular, 'new' = anlegen, sonst Record-Id (bearbeiten) const [editing, setEditing] = useState(null) const [form, setForm] = useState(emptyForm) const [errors, setErrors] = useState>>({}) const save = useMutation((body: CreateExhibitionResult) => editing && editing !== 'new' ? updateExhibitionResult(editing, body) : createExhibitionResult(body), ) const removal = useMutation((recordId: string) => deleteExhibitionResult(recordId)) const set = (key: K, value: FormState[K]) => setForm((f) => ({ ...f, [key]: value })) function openCreate() { setForm(emptyForm()) setErrors({}) setEditing('new') } function openEdit(r: ExhibitionResult) { setForm({ eventName: r.eventName, date: toDateInput(r.date as string | null), placement: r.placement ?? '', award: r.award ?? '', note: r.note ?? '', }) setErrors({}) setEditing(r.id) } async function onSubmit(e: FormEvent) { e.preventDefault() const next: Partial> = {} if (form.eventName.trim() === '') next.eventName = t.validation.eventNameRequired setErrors(next) if (Object.keys(next).length > 0) return const trimmed = (s: string) => (s.trim() === '' ? null : s.trim()) await save.run({ gerbilId, entityName, eventName: form.eventName.trim(), // date input gives "yyyy-MM-dd"; send as ISO so the backend DateTime? parses it. date: form.date ? `${form.date}T00:00:00Z` : null, placement: trimmed(form.placement), award: trimmed(form.award), note: trimmed(form.note), }) setEditing(null) records.reload() } async function onDelete(recordId: string) { if (!window.confirm(t.deleteConfirm)) return await removal.run(recordId) records.reload() } return (
{editing === null && ( )} {editing !== null && (

{editing === 'new' ? t.createTitle : t.editTitle}