import React, { useState, useEffect } from 'react'; import Button from './ui/Button'; import { Input, Textarea } from './ui/FormField'; function widthToSpan(pct) { if (pct <= 8) return 1; if (pct <= 17) return 2; if (pct <= 25) return 3; if (pct <= 33) return 4; if (pct <= 42) return 5; if (pct <= 50) return 6; if (pct <= 67) return 8; if (pct <= 75) return 9; return 12; } import Alert from './ui/Alert'; import { animalsApi, experimentsApi } from '../api/client'; export default function SubjectInfoForm({ animal, subjectTemplate = [], experimentId, onTemplateUpdate, onSaved, onCancel }) { const activeFields = subjectTemplate.filter((f) => f.active); function buildInitialValues() { const vals = {}; for (const f of activeFields) { vals[f.key] = animal?.subject_info?.[f.fieldId] ?? ''; } return vals; } const [values, setValues] = useState(buildInitialValues); const [apiError, setApiError] = useState(null); const [loading, setLoading] = useState(false); const [savingTagFor, setSavingTagFor] = useState(null); useEffect(() => { setValues(buildInitialValues()); setApiError(null); }, [animal, subjectTemplate]); const set = (key) => (e) => setValues((v) => ({ ...v, [key]: e.target.value })); async function saveTag(field) { const value = (values[field.key] ?? '').trim(); if (!value || !experimentId || !onTemplateUpdate) return; setSavingTagFor(field.fieldId); try { const updatedTemplate = subjectTemplate.map((f) => f.fieldId === field.fieldId ? { ...f, tags: [...(f.tags ?? []), value] } : f ); await experimentsApi.updateSubjectTemplate(experimentId, updatedTemplate); onTemplateUpdate(updatedTemplate); } catch (_) { } finally { setSavingTagFor(null); } } async function handleSubmit(e) { e.preventDefault(); setLoading(true); setApiError(null); try { // Preserve any fields not in the current active template const existing = animal?.subject_info ?? {}; const updates = {}; for (const f of activeFields) { updates[f.fieldId] = values[f.key] || null; } const merged = { ...existing, ...updates }; const updated = await animalsApi.update(animal.id, { subject_info: merged }); onSaved(updated); } catch (err) { setApiError(err); } finally { setLoading(false); } } if (activeFields.length === 0) { return (
No subject info fields configured for this experiment.
Use "Subject Template" on the experiment page to add fields.