From 29fa0bd02bc349d051dcb589600882de5c50b9f4 Mon Sep 17 00:00:00 2001 From: Chris Farhood Date: Wed, 20 May 2026 02:44:14 +0000 Subject: [PATCH] feat(GRO-1174): add pet size/coat dropdowns to booking wizard - Add Pet Size dropdown (Small, Medium, Large, X-Large) after breed field - Add Coat Type dropdown (Smooth, Double, Curly, Wire, Long, Hairless) - Pass petSizeCategory + petCoatType as query params to availability endpoint - Include petSizeCategory + petCoatType in POST /appointments body - Show "appointment" duration label on confirm (service duration only) - Display pet size/coat on confirmation card when provided - Pre-fill from URL params - Reset form resets all new fields Co-Authored-By: Paperclip --- src/pages/Book.tsx | 64 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/src/pages/Book.tsx b/src/pages/Book.tsx index dc58c9b..495c440 100644 --- a/src/pages/Book.tsx +++ b/src/pages/Book.tsx @@ -13,6 +13,8 @@ interface BookingBody { petName: string; petSpecies: string; petBreed: string; + petSizeCategory: string; + petCoatType: string; notes: string; } @@ -123,6 +125,8 @@ export function BookPage() { petName: "", petSpecies: "", petBreed: "", + petSizeCategory: "", + petCoatType: "", notes: "", }); const [formError, setFormError] = useState(null); @@ -136,7 +140,9 @@ export function BookPage() { const petName = searchParams.get("petName"); const petSpecies = searchParams.get("petSpecies"); const petBreed = searchParams.get("petBreed"); - if (clientName || clientEmail || clientPhone || petName || petSpecies || petBreed) { + const petSizeCategory = searchParams.get("petSizeCategory"); + const petCoatType = searchParams.get("petCoatType"); + if (clientName || clientEmail || clientPhone || petName || petSpecies || petBreed || petSizeCategory || petCoatType) { setForm((f) => ({ ...f, ...(clientName && { clientName }), @@ -145,6 +151,8 @@ export function BookPage() { ...(petName && { petName }), ...(petSpecies && { petSpecies }), ...(petBreed && { petBreed }), + ...(petSizeCategory && { petSizeCategory }), + ...(petCoatType && { petCoatType }), })); } }, [searchParams]); @@ -168,14 +176,18 @@ export function BookPage() { if (!selectedService || !date) return; setSlotsLoading(true); setSelectedSlot(null); - fetch( - `/api/book/availability?serviceId=${encodeURIComponent(selectedService.id)}&date=${encodeURIComponent(date)}` - ) + const params = new URLSearchParams({ + serviceId: selectedService.id, + date, + }); + if (form.petSizeCategory) params.set("petSizeCategory", form.petSizeCategory); + if (form.petCoatType) params.set("petCoatType", form.petCoatType); + fetch(`/api/book/availability?${params.toString()}`) .then((r) => r.json() as Promise) .then(setSlots) .catch(() => setSlots([])) .finally(() => setSlotsLoading(false)); - }, [selectedService, date]); + }, [selectedService, date, form.petSizeCategory, form.petCoatType]); function goToStep2(svc: Service) { setSelectedService(svc); @@ -214,6 +226,8 @@ export function BookPage() { petName: form.petName, petSpecies: form.petSpecies, petBreed: form.petBreed || undefined, + petSizeCategory: form.petSizeCategory || undefined, + petCoatType: form.petCoatType || undefined, notes: form.notes || undefined, }), }); @@ -494,6 +508,36 @@ export function BookPage() { placeholder="Golden Retriever" /> +
+ + +
+
+ + +