diff --git a/src/portal/sections/PetForm.tsx b/src/portal/sections/PetForm.tsx index f0c3610..5e195a4 100644 --- a/src/portal/sections/PetForm.tsx +++ b/src/portal/sections/PetForm.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { X, Save, Plus, Star } from "lucide-react"; +import { X, Save, Plus, Star, Loader2 } from "lucide-react"; import type { Pet, MedicalAlert, CoatType, AlertSeverity } from "@groombook/types"; const COAT_TYPES: CoatType[] = ["double", "wire", "curly", "smooth", "long", "hairless"]; @@ -9,15 +9,17 @@ type SizeOption = typeof SIZE_OPTIONS[number]; interface Props { pet?: Pet; - onSave: (pet: Pet) => void; + onSave: (pet: Pet) => void | Promise; onCancel: () => void; + saving?: boolean; + saveError?: string | null; } function newAlert(): Omit { return { type: "", description: "", severity: "low" }; } -export function PetForm({ pet, onSave, onCancel }: Props) { +export function PetForm({ pet, onSave, onCancel, saving, saveError }: Props) { const [name, setName] = useState(pet?.name ?? ""); const [breed, setBreed] = useState(pet?.breed ?? ""); const [weight, setWeight] = useState(pet?.weightKg ?? 0); @@ -305,18 +307,23 @@ export function PetForm({ pet, onSave, onCancel }: Props) { + {saveError && ( +

{saveError}

+ )} ); diff --git a/src/portal/sections/PetProfiles.tsx b/src/portal/sections/PetProfiles.tsx index 6f0fdb6..412b475 100644 --- a/src/portal/sections/PetProfiles.tsx +++ b/src/portal/sections/PetProfiles.tsx @@ -83,9 +83,27 @@ export function PetProfiles({ sessionId, readOnly }: Props) { const petHistory = appointments.appointments.filter(a => a.pet?.id === selectedPetId && new Date(a.startTime) <= new Date()); const editingPet = editingPetId ? pets.find(p => p.id === editingPetId) ?? null : null; - function handlePetSave(updatedPet: Pet) { - setPets(prev => prev.map(p => p.id === updatedPet.id ? updatedPet : p)); - setEditingPetId(null); + const [saving, setSaving] = useState(false); + const [saveError, setSaveError] = useState(null); + + async function handlePetSave(updatedPet: Pet) { + setSaving(true); + setSaveError(null); + try { + const res = await fetch(`/api/portal/pets/${updatedPet.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json", ...buildHeaders(sessionId) }, + body: JSON.stringify(updatedPet), + }); + if (!res.ok) throw new Error("Failed to save pet"); + const saved: Pet = await res.json(); + setPets(prev => prev.map(p => p.id === saved.id ? saved : p)); + setEditingPetId(null); + } catch (e) { + setSaveError(e instanceof Error ? e.message : "Failed to save pet"); + } finally { + setSaving(false); + } } if (editingPet) { @@ -94,6 +112,8 @@ export function PetProfiles({ sessionId, readOnly }: Props) { pet={editingPet} onSave={handlePetSave} onCancel={() => setEditingPetId(null)} + saving={saving} + saveError={saveError} /> ); }