97 lines
2.9 KiB
React
97 lines
2.9 KiB
React
import React, { useState, useEffect } from 'react';
|
|
import Button from './ui/Button';
|
|
import FormField, { Input } from './ui/FormField';
|
|
import Alert from './ui/Alert';
|
|
import { animalsApi } from '../api/client';
|
|
|
|
export default function AnimalForm({ existing, experimentId, onSuccess, onCancel }) {
|
|
const [fields, setFields] = useState({
|
|
animal_id_string: existing?.animal_id_string ?? '',
|
|
animal_name: existing?.animal_name ?? '',
|
|
});
|
|
const [errors, setErrors] = useState({});
|
|
const [apiError, setApiError] = useState(null);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setFields({
|
|
animal_id_string: existing?.animal_id_string ?? '',
|
|
animal_name: existing?.animal_name ?? '',
|
|
});
|
|
setErrors({});
|
|
setApiError(null);
|
|
}, [existing]);
|
|
|
|
const set = (k) => (e) => setFields((f) => ({ ...f, [k]: e.target.value }));
|
|
|
|
function validate() {
|
|
const e = {};
|
|
if (!fields.animal_id_string.trim()) e.animal_id_string = 'Animal ID is required';
|
|
if (!fields.animal_name.trim()) e.animal_name = 'Animal name is required';
|
|
setErrors(e);
|
|
return Object.keys(e).length === 0;
|
|
}
|
|
|
|
async function handleSubmit(e) {
|
|
e.preventDefault();
|
|
if (!validate()) return;
|
|
setLoading(true);
|
|
setApiError(null);
|
|
try {
|
|
const payload = {
|
|
animal_id_string: fields.animal_id_string.trim(),
|
|
animal_name: fields.animal_name.trim(),
|
|
};
|
|
const result = existing
|
|
? await animalsApi.update(existing.id, payload)
|
|
: await animalsApi.create({ ...payload, experiment_id: experimentId });
|
|
onSuccess(result);
|
|
} catch (err) {
|
|
setApiError(err);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit} noValidate className="space-y-4">
|
|
{apiError && (
|
|
<Alert
|
|
type="error"
|
|
message={apiError.message}
|
|
details={apiError.details}
|
|
onDismiss={() => setApiError(null)}
|
|
/>
|
|
)}
|
|
<FormField label="Animal ID" name="animal_id_string" error={errors.animal_id_string} required>
|
|
<Input
|
|
name="animal_id_string"
|
|
value={fields.animal_id_string}
|
|
onChange={set('animal_id_string')}
|
|
placeholder="e.g. M-001"
|
|
required
|
|
disabled={loading}
|
|
/>
|
|
</FormField>
|
|
<FormField label="Animal Name" name="animal_name" error={errors.animal_name} required>
|
|
<Input
|
|
name="animal_name"
|
|
value={fields.animal_name}
|
|
onChange={set('animal_name')}
|
|
placeholder="e.g. Whiskers"
|
|
required
|
|
disabled={loading}
|
|
/>
|
|
</FormField>
|
|
<div className="flex justify-end gap-3 pt-2">
|
|
<Button variant="secondary" type="button" onClick={onCancel} disabled={loading}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" loading={loading}>
|
|
{existing ? 'Save Changes' : 'Add Animal'}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|