Fix profile images
This commit is contained in:
@@ -615,15 +615,7 @@ function AppointmentsPage() {
|
|||||||
{submitting ? "Booking..." : isAdoptionService ? "Schedule Adoption Visit" : "Book Appointment"}
|
{submitting ? "Booking..." : isAdoptionService ? "Schedule Adoption Visit" : "Book Appointment"}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
) : (
|
) : null}
|
||||||
<div className="appt-form">
|
|
||||||
<h2 className="appt-form-title">Appointment Booking</h2>
|
|
||||||
<div className="appt-service-info">
|
|
||||||
<p>Web appointment booking is currently available for customer accounts only.</p>
|
|
||||||
<p>Admin and staff accounts can still review appointment activity below.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="appt-history">
|
<div className="appt-history">
|
||||||
<h2 className="appt-form-title">{canBookAppointments ? "Your Appointments" : "Appointments"}</h2>
|
<h2 className="appt-form-title">{canBookAppointments ? "Your Appointments" : "Appointments"}</h2>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState, useCallback } from "react";
|
import { useEffect, useState, useCallback, useRef } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useAuth } from "@/context/AuthContext";
|
import { useAuth } from "@/context/AuthContext";
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ const API_BASE = "";
|
|||||||
export default function ProfilePage() {
|
export default function ProfilePage() {
|
||||||
const {user, token, loading, logout, refreshUser} = useAuth();
|
const {user, token, loading, logout, refreshUser} = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const petImageObjectUrlsRef = useRef([]);
|
||||||
|
|
||||||
const [pets, setPets] = useState([]);
|
const [pets, setPets] = useState([]);
|
||||||
const [loadingPets, setLoadingPets] = useState(false);
|
const [loadingPets, setLoadingPets] = useState(false);
|
||||||
@@ -25,6 +26,13 @@ export default function ProfilePage() {
|
|||||||
const [profileSuccess, setProfileSuccess] = useState(null);
|
const [profileSuccess, setProfileSuccess] = useState(null);
|
||||||
const [avatarSubmitting, setAvatarSubmitting] = useState(false);
|
const [avatarSubmitting, setAvatarSubmitting] = useState(false);
|
||||||
|
|
||||||
|
const clearPetImageObjectUrls = useCallback(() => {
|
||||||
|
for (const objectUrl of petImageObjectUrlsRef.current) {
|
||||||
|
URL.revokeObjectURL(objectUrl);
|
||||||
|
}
|
||||||
|
petImageObjectUrlsRef.current = [];
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && !user) {
|
if (!loading && !user) {
|
||||||
router.replace(`/login?next=${encodeURIComponent("/profile")}`);
|
router.replace(`/login?next=${encodeURIComponent("/profile")}`);
|
||||||
@@ -40,17 +48,64 @@ export default function ProfilePage() {
|
|||||||
});
|
});
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
const loadPets = useCallback(() => {
|
const loadPets = useCallback(async () => {
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
setLoadingPets(true);
|
setLoadingPets(true);
|
||||||
fetch(`${API_BASE}/api/v1/my-pets`, {
|
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
try {
|
||||||
})
|
const response = await fetch(`${API_BASE}/api/v1/my-pets`, {
|
||||||
.then((r) => r.json())
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
.then(setPets)
|
});
|
||||||
.catch(() => {})
|
|
||||||
.finally(() => setLoadingPets(false));
|
if (!response.ok) {
|
||||||
}, [token]);
|
throw new Error(`Request failed (${response.status})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const petData = await response.json();
|
||||||
|
clearPetImageObjectUrls();
|
||||||
|
|
||||||
|
const petsWithResolvedImages = await Promise.all(
|
||||||
|
(Array.isArray(petData) ? petData : []).map(async (pet) => {
|
||||||
|
if (!pet.imageUrl) {
|
||||||
|
return pet;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const imageResponse = await fetch(`${API_BASE}${pet.imageUrl}`, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!imageResponse.ok) {
|
||||||
|
return { ...pet, imageUrl: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = await imageResponse.blob();
|
||||||
|
const objectUrl = URL.createObjectURL(blob);
|
||||||
|
petImageObjectUrlsRef.current.push(objectUrl);
|
||||||
|
|
||||||
|
return { ...pet, imageUrl: objectUrl };
|
||||||
|
} catch {
|
||||||
|
return { ...pet, imageUrl: null };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setPets(petsWithResolvedImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch {
|
||||||
|
}
|
||||||
|
|
||||||
|
finally {
|
||||||
|
setLoadingPets(false);
|
||||||
|
}
|
||||||
|
}, [token, clearPetImageObjectUrls]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
clearPetImageObjectUrls();
|
||||||
|
};
|
||||||
|
}, [clearPetImageObjectUrls]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user?.role === "CUSTOMER") {
|
if (user?.role === "CUSTOMER") {
|
||||||
|
|||||||
Reference in New Issue
Block a user