From 4dabb25ee17cd2e6f6c7e450973e149d34fc3403 Mon Sep 17 00:00:00 2001 From: "groombook-engineer[bot]" <269742240+groombook-engineer[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2026 15:14:44 +0000 Subject: [PATCH] fix(portal/book): wire Rebook Now button + date format validation (GRO-265, GRO-266) * fix(portal): wire Rebook Now button to navigate to booking wizard (GRO-265) The "Rebook Now" button on the Report Card detail view had no click handler. Now navigates to /admin/book with pet info pre-filled via URL params (petName, serviceName). Button text changed from "Book Now" to "Rebook Now" per the bug report. Co-Authored-By: Paperclip * fix(book): pre-fill form from URL params to ensure React state is set Add useSearchParams to read URL parameters (e.g., ?clientName=Jane) and sync them to the BookingBody state on mount via useEffect. This ensures validation checks React state, not empty initial state. Fixes GRO-255 Co-Authored-By: Paperclip * fix(book): add inline validation for date input format (GRO-266) Date picker now shows a clear error when the value doesn't match YYYY-MM-DD, instead of silently failing with a browser console warning. Co-Authored-By: Paperclip * fix(portal): wire Rebook Now button + clean .js artifacts (GRO-265) Cherry-picked from contaminated PR #160: - ReportCards.tsx: Rebook Now button navigates to /admin/book with pet info - Book.tsx: pre-fill form from URL params (GRO-255) - Book.tsx: inline date validation (GRO-266) Also removes compiled .js artifacts (Book.js, ReportCards.js) that were incorrectly committed. Co-Authored-By: Paperclip --------- Co-authored-by: groombook-ci[bot] Co-authored-by: Paperclip --- apps/web/src/pages/Book.tsx | 39 +++++++++++++++++++- apps/web/src/portal/sections/ReportCards.tsx | 13 ++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/apps/web/src/pages/Book.tsx b/apps/web/src/pages/Book.tsx index 0e0710d..dc58c9b 100644 --- a/apps/web/src/pages/Book.tsx +++ b/apps/web/src/pages/Book.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; +import { useSearchParams } from "react-router-dom"; import type { Service } from "@groombook/types"; // ─── Types ─────────────────────────────────────────────────────────────────── @@ -107,6 +108,7 @@ export function BookPage() { // Step 2 — date & time const [date, setDate] = useState(todayIso()); + const [dateError, setDateError] = useState(null); const [slots, setSlots] = useState([]); const [slotsLoading, setSlotsLoading] = useState(false); const [selectedSlot, setSelectedSlot] = useState(null); @@ -125,6 +127,28 @@ export function BookPage() { }); const [formError, setFormError] = useState(null); + // Pre-fill form from URL params (e.g., ?clientName=Jane&clientEmail=jane@example.com) + const [searchParams] = useSearchParams(); + useEffect(() => { + const clientName = searchParams.get("clientName"); + const clientEmail = searchParams.get("clientEmail"); + const clientPhone = searchParams.get("clientPhone"); + const petName = searchParams.get("petName"); + const petSpecies = searchParams.get("petSpecies"); + const petBreed = searchParams.get("petBreed"); + if (clientName || clientEmail || clientPhone || petName || petSpecies || petBreed) { + setForm((f) => ({ + ...f, + ...(clientName && { clientName }), + ...(clientEmail && { clientEmail }), + ...(clientPhone && { clientPhone }), + ...(petName && { petName }), + ...(petSpecies && { petSpecies }), + ...(petBreed && { petBreed }), + })); + } + }, [searchParams]); + // Step 4 — result const [submitting, setSubmitting] = useState(false); const [result, setResult] = useState(null); @@ -328,8 +352,21 @@ export function BookPage() { value={date} min={todayIso()} style={{ ...input, width: "auto" }} - onChange={(e) => setDate(e.target.value)} + onChange={(e) => { + const val = e.target.value; + // HTML5 date input enforces yyyy-MM-dd; empty value means invalid format + if (!val) { + setDateError("Please enter a valid date (YYYY-MM-DD)."); + setDate(""); + } else { + setDateError(null); + setDate(val); + } + }} /> + {dateError && ( +

{dateError}

+ )}
diff --git a/apps/web/src/portal/sections/ReportCards.tsx b/apps/web/src/portal/sections/ReportCards.tsx index f1136a3..a8d471b 100644 --- a/apps/web/src/portal/sections/ReportCards.tsx +++ b/apps/web/src/portal/sections/ReportCards.tsx @@ -241,8 +241,17 @@ function ReportCardDetail({ card, onBack }: { card: Appointment; onBack: () => v

Book your next visit

Schedule your next grooming appointment

-