@@ -150,23 +160,56 @@ function PasswordChange({ readOnly }: { readOnly: boolean }) {
);
}
+ function handleSubmit() {
+ if (!canSubmit) return;
+ if (newPassword !== confirmPassword) {
+ setError("Passwords do not match.");
+ return;
+ }
+ // TODO: Wire up to actual password-change API endpoint once backend support exists
+ setError(null);
+ setCurrentPassword("");
+ setNewPassword("");
+ setConfirmPassword("");
+ }
+
return (
Change Password
@@ -185,7 +228,9 @@ function ManagePets({ sessionId, readOnly }: { sessionId: string | null; readOnl
const fetchPets = async () => {
try {
setLoading(true);
- const response = await fetch("/api/portal/pets");
+ const response = await fetch("/api/portal/pets", {
+ headers: { "X-Impersonation-Session-Id": sessionId ?? "" },
+ });
if (response.ok) {
const data = await response.json();
setPets(Array.isArray(data) ? data : []);
@@ -225,7 +270,6 @@ function ManagePets({ sessionId, readOnly }: { sessionId: string | null; readOnl
{ 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 03fcad1..2eb6bc1 100644
--- a/apps/web/src/portal/sections/Appointments.tsx
+++ b/apps/web/src/portal/sections/Appointments.tsx
@@ -118,7 +118,7 @@ export const AppointmentsSection: React.FC = ({ sessio
try {
const response = await fetch('/api/portal/appointments', {
- headers: { Authorization: `Bearer ${sessionId}` },
+ headers: { "X-Impersonation-Session-Id": sessionId ?? "" },
});
if (response.ok) {
@@ -744,10 +744,10 @@ function BookingFlow({ onClose, sessionId }: BookingFlowProps) {
try {
const [petsRes, servicesRes] = await Promise.all([
fetch('/api/portal/pets', {
- headers: { Authorization: `Bearer ${sessionId}` },
+ headers: { "X-Impersonation-Session-Id": sessionId ?? "" },
}),
fetch('/api/portal/services', {
- headers: { Authorization: `Bearer ${sessionId}` },
+ headers: { "X-Impersonation-Session-Id": sessionId ?? "" },
}),
]);
diff --git a/apps/web/src/portal/sections/ReportCards.tsx b/apps/web/src/portal/sections/ReportCards.tsx
index a8d471b..018b376 100644
--- a/apps/web/src/portal/sections/ReportCards.tsx
+++ b/apps/web/src/portal/sections/ReportCards.tsx
@@ -1,4 +1,4 @@
-import { useState, useEffect } from "react";
+import { useState, useEffect, useRef } from "react";
import { FileText, Share2, Calendar, Smile, Meh, ChevronRight, Loader2 } from "lucide-react";
type MoodKey = "calm" | "cooperative" | "anxious" | "wiggly";
@@ -24,36 +24,44 @@ interface Appointment {
reportCardId?: string;
}
-export function ReportCards() {
+interface Props {
+ sessionId: string | null;
+}
+
+export function ReportCards({ sessionId }: Props) {
const [appointments, setAppointments] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
const [selectedCard, setSelectedCard] = useState(null);
- useEffect(() => {
- const fetchReportCards = async () => {
- try {
- const response = await fetch("/api/portal/appointments");
+ const fetchReportCardsRef = useRef<() => Promise>(async () => {
+ setIsLoading(true);
+ setError(null);
+ try {
+ const response = await fetch("/api/portal/appointments", {
+ headers: { "X-Impersonation-Session-Id": sessionId ?? "" },
+ });
- if (response.ok) {
- const data = await response.json();
- const allAppointments: Appointment[] = data.appointments || data || [];
- const reportCardAppointments = allAppointments.filter(
- (appt) => appt.reportCardId
- );
- setAppointments(reportCardAppointments);
- } else {
- setError("Failed to load report cards.");
- }
- } catch {
- setError("Failed to load report cards. Please try again.");
- } finally {
- setIsLoading(false);
+ if (response.ok) {
+ const data = await response.json();
+ const allAppointments: Appointment[] = data.appointments || data || [];
+ const reportCardAppointments = allAppointments.filter(
+ (appt) => appt.reportCardId
+ );
+ setAppointments(reportCardAppointments);
+ } else {
+ setError("Failed to load report cards.");
}
- };
+ } catch {
+ setError("Failed to load report cards. Please try again.");
+ } finally {
+ setIsLoading(false);
+ }
+ });
- fetchReportCards();
- }, []);
+ useEffect(() => {
+ void fetchReportCardsRef.current();
+ }, [sessionId]);
if (isLoading) {
return (
@@ -69,7 +77,7 @@ export function ReportCards() {
{error}