From 2a871a4d41c6deca6ac4d96615b42e6250b8f696 Mon Sep 17 00:00:00 2001 From: augmentedpotato Date: Thu, 2 Apr 2026 09:08:00 -0600 Subject: [PATCH] Fix item loading --- web/app/adopt/page.js | 30 +++++++++++++++++++----------- web/app/products/page.js | 32 +++++++++++++++++--------------- web/components/PetCard.js | 10 +++++++++- web/components/PetProfile.js | 10 +++++++++- web/components/ProductCard.js | 10 +++++++++- web/components/ProductProfile.js | 10 +++++++++- web/lib/fetchAllPages.js | 19 +++++++++++++++++++ 7 files changed, 91 insertions(+), 30 deletions(-) create mode 100644 web/lib/fetchAllPages.js diff --git a/web/app/adopt/page.js b/web/app/adopt/page.js index 90293d8c..97fe1472 100644 --- a/web/app/adopt/page.js +++ b/web/app/adopt/page.js @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import PetCard from "@/components/PetCard"; +import { fetchAllPages } from "@/lib/fetchAllPages"; const API_BASE = ""; @@ -13,7 +14,7 @@ export default function AdoptPage() { const [search, setSearch] = useState(""); const [query, setQuery] = useState(""); - const PAGE_SIZE = 200; + const PAGE_SIZE = 100; useEffect(() => { fetch(`${API_BASE}/api/v1/health`) @@ -22,16 +23,23 @@ export default function AdoptPage() { }, []); useEffect(() => { - const params = new URLSearchParams({ page: 0, size: PAGE_SIZE, sort: "petId,asc" }); - if (query) params.set("q", query); + setLoading(true); + setError(null); - fetch(`${API_BASE}/api/v1/pets?${params}`) - .then((res) => { - if (!res.ok) throw new Error(`HTTP ${res.status} – ${res.statusText}`); - return res.json(); - }) - .then((data) => { - setPets(data.content ?? []); + fetchAllPages((page) => { + const params = new URLSearchParams({ + page: String(page), + size: String(PAGE_SIZE), + sort: "petId,asc", + status: "Available", + }); + if (query) { + params.set("q", query); + } + return `${API_BASE}/api/v1/pets?${params}`; + }) + .then((allPets) => { + setPets(allPets); }) .catch((err) => setError(err.message)) .finally(() => setLoading(false)); @@ -58,7 +66,7 @@ export default function AdoptPage() { setSearch(e.target.value)} /> diff --git a/web/app/products/page.js b/web/app/products/page.js index b3416326..19cf8670 100644 --- a/web/app/products/page.js +++ b/web/app/products/page.js @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import ProductCard from "@/components/ProductCard"; +import { fetchAllPages } from "@/lib/fetchAllPages"; const API_BASE = ""; @@ -12,24 +13,25 @@ export default function ProductsPage() { const [search, setSearch] = useState(""); const [query, setQuery] = useState(""); - const PAGE_SIZE = 200; + const PAGE_SIZE = 100; useEffect(() => { - const params = new URLSearchParams({ page: 0, size: PAGE_SIZE, sort: "prodId,asc" }); - if (query) { - params.set("q", query); - } + setLoading(true); + setError(null); - fetch(`${API_BASE}/api/v1/products?${params}`) - .then((res) => { - if (!res.ok) { - throw new Error(`HTTP ${res.status} – ${res.statusText}`); - } - - return res.json(); - }) - .then((data) => { - setProducts(data.content ?? []); + fetchAllPages((page) => { + const params = new URLSearchParams({ + page: String(page), + size: String(PAGE_SIZE), + sort: "prodId,asc", + }); + if (query) { + params.set("q", query); + } + return `${API_BASE}/api/v1/products?${params}`; + }) + .then((allProducts) => { + setProducts(allProducts); }) .catch((err) => setError(err.message)) .finally(() => setLoading(false)); diff --git a/web/components/PetCard.js b/web/components/PetCard.js index 4370bca1..4c6410b9 100644 --- a/web/components/PetCard.js +++ b/web/components/PetCard.js @@ -5,7 +5,15 @@ export default function PetCard({petId, petName, petSpecies, petStatus, imageUrl return (
- {petName} + {petName} { + e.currentTarget.onerror = null; + e.currentTarget.src = "/images/pet-placeholder.png"; + }} + />

{petName}

diff --git a/web/components/PetProfile.js b/web/components/PetProfile.js index a00732a4..8b7fd6f0 100644 --- a/web/components/PetProfile.js +++ b/web/components/PetProfile.js @@ -5,7 +5,15 @@ export default function PetProfile({ petId, petName, petSpecies, petBreed, petAg return (
- {petName} + {petName} { + e.currentTarget.onerror = null; + e.currentTarget.src = "/images/pet-placeholder.png"; + }} + />
diff --git a/web/components/ProductCard.js b/web/components/ProductCard.js index e27abbbd..0b4c76ed 100644 --- a/web/components/ProductCard.js +++ b/web/components/ProductCard.js @@ -4,7 +4,15 @@ export default function ProductCard({ prodId, prodName, categoryName, prodPrice, return (
- {prodName} + {prodName} { + e.currentTarget.onerror = null; + e.currentTarget.src = "/images/pet-placeholder.png"; + }} + />

{prodName}

diff --git a/web/components/ProductProfile.js b/web/components/ProductProfile.js index b8d0a9b2..fda41420 100644 --- a/web/components/ProductProfile.js +++ b/web/components/ProductProfile.js @@ -4,7 +4,15 @@ export default function ProductProfile({ prodName, categoryName, prodDesc, prodP return (
- {prodName} + {prodName} { + e.currentTarget.onerror = null; + e.currentTarget.src = "/images/pet-placeholder.png"; + }} + />
diff --git a/web/lib/fetchAllPages.js b/web/lib/fetchAllPages.js new file mode 100644 index 00000000..624d172c --- /dev/null +++ b/web/lib/fetchAllPages.js @@ -0,0 +1,19 @@ +export async function fetchAllPages(urlBuilder) { + const items = []; + let page = 0; + let totalPages = 1; + + while (page < totalPages) { + const res = await fetch(urlBuilder(page)); + if (!res.ok) { + throw new Error(`HTTP ${res.status} – ${res.statusText}`); + } + + const data = await res.json(); + items.push(...(data.content ?? [])); + totalPages = Math.max(data.totalPages ?? 1, 1); + page += 1; + } + + return items; +}