Fixes for appointments and My Pets fields.
This commit is contained in:
@@ -6,6 +6,18 @@ import { useAuth } from "@/context/AuthContext";
|
||||
|
||||
const API_BASE = "";
|
||||
|
||||
const SPECIES_BREEDS = {
|
||||
Dog: ["Beagle", "Boxer", "Bulldog", "Chihuahua", "Dachshund", "German Shepherd", "Golden Retriever", "Labrador Retriever", "Poodle", "Rottweiler", "Shih Tzu", "Siberian Husky", "Yorkshire Terrier", "Mixed / Other"],
|
||||
Cat: ["Abyssinian", "Bengal", "British Shorthair", "Maine Coon", "Persian", "Ragdoll", "Scottish Fold", "Siamese", "Sphynx", "Mixed / Other"],
|
||||
Bird: ["Canary", "Cockatiel", "Cockatoo", "Finch", "Lovebird", "Macaw", "Parakeet", "Parrot", "Other"],
|
||||
Rabbit: ["Dutch", "Flemish Giant", "Holland Lop", "Lionhead", "Mini Rex", "Other"],
|
||||
Hamster: ["Dwarf", "Roborovski", "Syrian", "Other"],
|
||||
"Guinea Pig": ["Abyssinian", "American", "Peruvian", "Teddy", "Other"],
|
||||
Reptile: ["Ball Python", "Bearded Dragon", "Blue-tongued Skink", "Corn Snake", "Leopard Gecko", "Other"],
|
||||
Fish: ["Angelfish", "Betta", "Cichlid", "Clownfish", "Goldfish", "Guppy", "Tetra", "Other"],
|
||||
Other: ["Other"],
|
||||
};
|
||||
|
||||
export default function ProfilePage() {
|
||||
const {user, token, loading, logout, refreshUser} = useAuth();
|
||||
const router = useRouter();
|
||||
@@ -53,7 +65,7 @@ export default function ProfilePage() {
|
||||
setLoadingPets(true);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/api/v1/my-pets`, {
|
||||
const response = await fetch(`${API_BASE}/api/v1/my-pets?status=Owned`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
@@ -64,25 +76,21 @@ export default function ProfilePage() {
|
||||
const petData = await response.json();
|
||||
clearPetImageObjectUrls();
|
||||
|
||||
const petsWithResolvedImages = await Promise.all(
|
||||
(Array.isArray(petData) ? petData : []).map(async (pet) => {
|
||||
if (!pet.imageUrl) {
|
||||
return pet;
|
||||
}
|
||||
const ownedPets = Array.isArray(petData) ? petData : [];
|
||||
|
||||
const petsWithResolvedImages = await Promise.all(
|
||||
ownedPets.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 };
|
||||
}
|
||||
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 };
|
||||
@@ -284,14 +292,19 @@ if (user?.role === "CUSTOMER" || user?.role === "ADMIN") {
|
||||
}
|
||||
|
||||
try {
|
||||
await fetch(`${API_BASE}/api/v1/my-pets/${id}`, {
|
||||
const res = await fetch(`${API_BASE}/api/v1/my-pets/${id}`, {
|
||||
method: "DELETE",
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => null);
|
||||
throw new Error(data?.message || `Failed to remove pet (${res.status})`);
|
||||
}
|
||||
loadPets();
|
||||
}
|
||||
|
||||
catch {
|
||||
|
||||
catch (err) {
|
||||
alert(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,26 +458,32 @@ if (user?.role === "CUSTOMER" || user?.role === "ADMIN") {
|
||||
</label>
|
||||
<label className="appt-label">
|
||||
Species
|
||||
<input
|
||||
className="appt-input"
|
||||
type="text"
|
||||
<select
|
||||
className="appt-select"
|
||||
value={species}
|
||||
onChange={(e) => setSpecies(e.target.value)}
|
||||
onChange={(e) => { setSpecies(e.target.value); setBreed(""); }}
|
||||
required
|
||||
maxLength={50}
|
||||
placeholder="e.g. Dog, Cat, Bird"
|
||||
/>
|
||||
>
|
||||
<option value="">Select a species...</option>
|
||||
{Object.keys(SPECIES_BREEDS).map((s) => (
|
||||
<option key={s} value={s}>{s}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="appt-label">
|
||||
Breed (optional)
|
||||
<input
|
||||
className="appt-input"
|
||||
type="text"
|
||||
Breed
|
||||
<select
|
||||
className="appt-select"
|
||||
value={breed}
|
||||
onChange={(e) => setBreed(e.target.value)}
|
||||
maxLength={50}
|
||||
placeholder="e.g. Golden Retriever"
|
||||
/>
|
||||
required
|
||||
disabled={!species}
|
||||
>
|
||||
<option value="">{species ? "Select a breed..." : "Select a species first"}</option>
|
||||
{(SPECIES_BREEDS[species] || []).map((b) => (
|
||||
<option key={b} value={b}>{b}</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<div className="profile-pet-form-actions">
|
||||
<button type="submit" className="appt-submit-btn" disabled={submitting}>
|
||||
@@ -514,11 +533,11 @@ if (user?.role === "CUSTOMER" || user?.role === "ADMIN") {
|
||||
{pet.breed && <span className="profile-pet-card-detail">{pet.breed}</span>}
|
||||
</div>
|
||||
<div className="profile-pet-card-actions">
|
||||
<button type="button" className="profile-pet-edit-btn" onClick={() => openEditForm(pet)}>Edit</button>
|
||||
<button type="button" className="profile-pet-delete-btn" onClick={() => handleDeletePet(pet.customerPetId)}>Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button type="button" className="profile-pet-edit-btn" onClick={() => openEditForm(pet)}>Edit</button>
|
||||
<button type="button" className="profile-pet-delete-btn" onClick={() => handleDeletePet(pet.customerPetId)}>Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user