/** * FEAT-6: Fotos-Tab — Galerie-Raster + Upload (multipart) + Löschen. * Erstes Foto nach sortOrder = Profilfoto (Badge). Endpunkte entstehen in * FEAT-1b Phase 2 (Pam) — bis dahin zeigt der Tab saubere deutsche * Fehler-/Leerzustände. */ import { useRef, useState, type FormEvent } from 'react' import { de } from '../strings/de' import { deleteGerbilPhoto, listGerbilPhotos, photoSrc, profilePhoto, uploadGerbilPhoto, } from '../api/photos' import { useApi, useMutation } from '../hooks/useApi' export default function GerbilPhotosTab({ gerbilId }: { gerbilId: string }) { const t = de.pages.tierTabs.photos const photos = useApi(() => listGerbilPhotos(gerbilId), [gerbilId]) const fileInput = useRef(null) const [caption, setCaption] = useState('') const [fileError, setFileError] = useState(null) const upload = useMutation((file: File) => uploadGerbilPhoto(gerbilId, file, caption.trim() === '' ? null : caption.trim()), ) const removal = useMutation((photoId: string) => deleteGerbilPhoto(photoId)) async function onUpload(e: FormEvent) { e.preventDefault() const file = fileInput.current?.files?.[0] if (!file) { setFileError(t.validation.fileRequired) return } setFileError(null) await upload.run(file) setCaption('') if (fileInput.current) fileInput.current.value = '' photos.reload() } async function onDelete(photoId: string) { if (!window.confirm(t.deleteConfirm)) return await removal.run(photoId) photos.reload() } const items = photos.data ?? [] const profile = profilePhoto(items) return (

{t.uploadTitle}

{upload.error &&
{upload.error}
}
{photos.loading &&

{de.common.loading}

} {photos.error && (
{photos.error}
)} {removal.error &&
{removal.error}
} {!photos.loading && !photos.error && items.length === 0 && (

{t.empty}

)} {items.length > 0 && (
    {[...items] .sort((a, b) => a.sortOrder - b.sortOrder) .map((p) => (
  • {p.caption
    {profile?.id === p.id && {t.profileBadge}}{' '} {p.caption ?? ''}
  • ))}
)}
) }