Fix item loading

This commit is contained in:
augmentedpotato
2026-04-02 09:08:00 -06:00
parent 4bd98ef06f
commit 2a871a4d41
7 changed files with 91 additions and 30 deletions

View File

@@ -2,6 +2,7 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import PetCard from "@/components/PetCard"; import PetCard from "@/components/PetCard";
import { fetchAllPages } from "@/lib/fetchAllPages";
const API_BASE = ""; const API_BASE = "";
@@ -13,7 +14,7 @@ export default function AdoptPage() {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const PAGE_SIZE = 200; const PAGE_SIZE = 100;
useEffect(() => { useEffect(() => {
fetch(`${API_BASE}/api/v1/health`) fetch(`${API_BASE}/api/v1/health`)
@@ -22,16 +23,23 @@ export default function AdoptPage() {
}, []); }, []);
useEffect(() => { useEffect(() => {
const params = new URLSearchParams({ page: 0, size: PAGE_SIZE, sort: "petId,asc" }); setLoading(true);
if (query) params.set("q", query); setError(null);
fetch(`${API_BASE}/api/v1/pets?${params}`) fetchAllPages((page) => {
.then((res) => { const params = new URLSearchParams({
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`); page: String(page),
return res.json(); size: String(PAGE_SIZE),
}) sort: "petId,asc",
.then((data) => { status: "Available",
setPets(data.content ?? []); });
if (query) {
params.set("q", query);
}
return `${API_BASE}/api/v1/pets?${params}`;
})
.then((allPets) => {
setPets(allPets);
}) })
.catch((err) => setError(err.message)) .catch((err) => setError(err.message))
.finally(() => setLoading(false)); .finally(() => setLoading(false));
@@ -58,7 +66,7 @@ export default function AdoptPage() {
<input <input
className="adopt-search-input" className="adopt-search-input"
type="text" type="text"
placeholder="Search by name or species..." placeholder="Search by name, species, or breed..."
value={search} value={search}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
/> />

View File

@@ -2,6 +2,7 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import ProductCard from "@/components/ProductCard"; import ProductCard from "@/components/ProductCard";
import { fetchAllPages } from "@/lib/fetchAllPages";
const API_BASE = ""; const API_BASE = "";
@@ -12,24 +13,25 @@ export default function ProductsPage() {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
const PAGE_SIZE = 200; const PAGE_SIZE = 100;
useEffect(() => { useEffect(() => {
const params = new URLSearchParams({ page: 0, size: PAGE_SIZE, sort: "prodId,asc" }); setLoading(true);
if (query) { setError(null);
params.set("q", query);
}
fetch(`${API_BASE}/api/v1/products?${params}`) fetchAllPages((page) => {
.then((res) => { const params = new URLSearchParams({
if (!res.ok) { page: String(page),
throw new Error(`HTTP ${res.status} ${res.statusText}`); size: String(PAGE_SIZE),
} sort: "prodId,asc",
});
return res.json(); if (query) {
}) params.set("q", query);
.then((data) => { }
setProducts(data.content ?? []); return `${API_BASE}/api/v1/products?${params}`;
})
.then((allProducts) => {
setProducts(allProducts);
}) })
.catch((err) => setError(err.message)) .catch((err) => setError(err.message))
.finally(() => setLoading(false)); .finally(() => setLoading(false));

View File

@@ -5,7 +5,15 @@ export default function PetCard({petId, petName, petSpecies, petStatus, imageUrl
return ( return (
<Link href={`/adopt/${petId}`} className="pet-card"> <Link href={`/adopt/${petId}`} className="pet-card">
<div className="pet-card-image-wrapper"> <div className="pet-card-image-wrapper">
<img src={imageUrl || "/images/pet-placeholder.png"} alt={petName} className="pet-card-image" /> <img
src={imageUrl || "/images/pet-placeholder.png"}
alt={petName}
className="pet-card-image"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
</div> </div>
<div className="pet-card-body"> <div className="pet-card-body">
<h3 className="pet-card-name">{petName}</h3> <h3 className="pet-card-name">{petName}</h3>

View File

@@ -5,7 +5,15 @@ export default function PetProfile({ petId, petName, petSpecies, petBreed, petAg
return ( return (
<div className="pet-detail-card"> <div className="pet-detail-card">
<div className="pet-detail-image-wrapper"> <div className="pet-detail-image-wrapper">
<img src={imageUrl || "/images/pet-placeholder.png"} alt={petName} className="pet-detail-image" /> <img
src={imageUrl || "/images/pet-placeholder.png"}
alt={petName}
className="pet-detail-image"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
</div> </div>
<div className="pet-detail-info"> <div className="pet-detail-info">

View File

@@ -4,7 +4,15 @@ export default function ProductCard({ prodId, prodName, categoryName, prodPrice,
return ( return (
<Link href={`/products/${prodId}`} className="pet-card"> <Link href={`/products/${prodId}`} className="pet-card">
<div className="pet-card-image-wrapper"> <div className="pet-card-image-wrapper">
<img src={imageUrl || "/images/product-placeholder.png"} alt={prodName} className="pet-card-image" /> <img
src={imageUrl || "/images/pet-placeholder.png"}
alt={prodName}
className="pet-card-image"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
</div> </div>
<div className="pet-card-body"> <div className="pet-card-body">
<h3 className="pet-card-name">{prodName}</h3> <h3 className="pet-card-name">{prodName}</h3>

View File

@@ -4,7 +4,15 @@ export default function ProductProfile({ prodName, categoryName, prodDesc, prodP
return ( return (
<div className="pet-detail-card"> <div className="pet-detail-card">
<div className="pet-detail-image-wrapper"> <div className="pet-detail-image-wrapper">
<img src={imageUrl || "/images/product-placeholder.png"} alt={prodName} className="pet-detail-image" /> <img
src={imageUrl || "/images/pet-placeholder.png"}
alt={prodName}
className="pet-detail-image"
onError={(e) => {
e.currentTarget.onerror = null;
e.currentTarget.src = "/images/pet-placeholder.png";
}}
/>
</div> </div>
<div className="pet-detail-info"> <div className="pet-detail-info">

19
web/lib/fetchAllPages.js Normal file
View File

@@ -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;
}