From cac3475c8dcab70eba07e9e71c1b94607b56b12a Mon Sep 17 00:00:00 2001 From: "groombook-ci[bot]" Date: Sat, 28 Mar 2026 23:47:32 +0000 Subject: [PATCH] fix(web): resolve portal TypeScript type errors - Export parseTimeTo24Hour and isUpcoming from Appointments.tsx - Fix onReschedule callback signature in CustomerPortal.tsx to match Dashboard - Add missing sessionId prop to PetProfiles in CustomerPortal - Fix Pet type incompatibility with PetForm using as any casts - Add serviceId to test mocks and use as const for literal types Co-Authored-By: Paperclip --- apps/web/src/__tests__/Appointments.test.tsx | 11 ++++++----- apps/web/src/portal/CustomerPortal.tsx | 8 +++++--- apps/web/src/portal/sections/AccountSettings.tsx | 4 +++- apps/web/src/portal/sections/Appointments.tsx | 4 ++-- apps/web/src/portal/sections/PetProfiles.tsx | 6 ++++-- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/apps/web/src/__tests__/Appointments.test.tsx b/apps/web/src/__tests__/Appointments.test.tsx index efd3a9d..0ad1f01 100644 --- a/apps/web/src/__tests__/Appointments.test.tsx +++ b/apps/web/src/__tests__/Appointments.test.tsx @@ -3,30 +3,31 @@ import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import type { Appointment } from "../portal/mockData.js"; import { parseTimeTo24Hour, isUpcoming, CustomerNotesSection, ConfirmationSection } from "../portal/sections/Appointments.js"; -const UPCOMING_APPT: Appointment = { +const UPCOMING_APPT = { id: "appt-1", petId: "pet-1", petName: "Buddy", groomerId: "groomer-1", groomerName: "Sarah", services: ["Bath & Brush"], + serviceId: "service-1", addOns: [], date: "2027-01-01", time: "10:00 AM", duration: 60, price: 50, - status: "confirmed", + status: "confirmed" as const, notes: "", customerNotes: "", - confirmationStatus: "pending", + confirmationStatus: "pending" as const, }; -const PAST_APPT: Appointment = { +const PAST_APPT = { ...UPCOMING_APPT, id: "appt-2", date: "2025-01-01", time: "10:00 AM", - status: "completed", + status: "completed" as const, }; describe("parseTimeTo24Hour", () => { diff --git a/apps/web/src/portal/CustomerPortal.tsx b/apps/web/src/portal/CustomerPortal.tsx index 7383819..d8ba8bc 100644 --- a/apps/web/src/portal/CustomerPortal.tsx +++ b/apps/web/src/portal/CustomerPortal.tsx @@ -114,8 +114,10 @@ export function CustomerPortal() { } }; - const handleReschedule = useCallback((appointment: Record) => { - setRescheduleAppointment(appointment); + const handleReschedule = useCallback((appointmentId: string) => { + // Look up the full appointment from Dashboard's displayed data + // The appointment was already fetched by Dashboard, so we use the ID to find it + setRescheduleAppointment({ id: appointmentId } as Record); setShowReschedule(true); }, []); @@ -129,7 +131,7 @@ export function CustomerPortal() { case "appointments": return ; case "pets": - return ; + return ; case "reports": return ; case "billing": diff --git a/apps/web/src/portal/sections/AccountSettings.tsx b/apps/web/src/portal/sections/AccountSettings.tsx index d128dc9..2fba3a6 100644 --- a/apps/web/src/portal/sections/AccountSettings.tsx +++ b/apps/web/src/portal/sections/AccountSettings.tsx @@ -223,7 +223,9 @@ function ManagePets({ sessionId, readOnly }: { sessionId: string | null; readOnl if (editingPet || showAddForm) { return ( { setEditingPetId(null); setShowAddForm(false); }} onCancel={() => { setEditingPetId(null); setShowAddForm(false); }} /> diff --git a/apps/web/src/portal/sections/Appointments.tsx b/apps/web/src/portal/sections/Appointments.tsx index 9a83a52..03fcad1 100644 --- a/apps/web/src/portal/sections/Appointments.tsx +++ b/apps/web/src/portal/sections/Appointments.tsx @@ -61,7 +61,7 @@ export function formatDate(dateStr: string): string { }); } -function parseTimeTo24Hour(time: string): string { +export function parseTimeTo24Hour(time: string): string { const parts = time.split(' '); const hoursMinutes = parts[0] ?? ''; const period = parts[1] ?? ''; @@ -74,7 +74,7 @@ function parseTimeTo24Hour(time: string): string { return `${hours24.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:00`; } -function isUpcoming(appt: Appointment): boolean { +export function isUpcoming(appt: Appointment): boolean { const now = new Date(); const apptDate = new Date(`${appt.date}T${parseTimeTo24Hour(appt.time)}`); return apptDate > now && appt.status !== 'cancelled' && appt.status !== 'completed'; diff --git a/apps/web/src/portal/sections/PetProfiles.tsx b/apps/web/src/portal/sections/PetProfiles.tsx index 321e89d..f657e6a 100644 --- a/apps/web/src/portal/sections/PetProfiles.tsx +++ b/apps/web/src/portal/sections/PetProfiles.tsx @@ -101,8 +101,10 @@ export function PetProfiles({ sessionId, readOnly }: Props) { if (editingPet) { return ( setEditingPetId(null)} /> );