diff --git a/web/app/about/page.js b/web/app/about/page.js
new file mode 100644
index 00000000..5ba61fe2
--- /dev/null
+++ b/web/app/about/page.js
@@ -0,0 +1,37 @@
+export default function AboutPage() {
+ return (
+
+
+ About Leon's Pet Store
+ Pet care, adoption support, grooming, and everyday essentials in one place.
+
+
+
+
+
+
What We Do
+
+ Leon's Pet Store connects families with adoptable pets, helpful services, and quality products for day-to-day pet care.
+
+
+
+
+
Our Focus
+
+ - Support responsible pet adoption
+ - Provide grooming and care services
+ - Offer reliable pet supplies and essentials
+ - Create a friendly experience for customers and staff
+
+
+
+
+
Visit the Store
+
+ Browse adoptable pets, schedule appointments, shop products, or contact the team for help finding the right fit for a pet and household.
+
+
+
+
+ );
+}
diff --git a/web/app/adopt/[id]/page.js b/web/app/adopt/[id]/page.js
index 0834ca01..6c7b70e0 100644
--- a/web/app/adopt/[id]/page.js
+++ b/web/app/adopt/[id]/page.js
@@ -15,8 +15,6 @@ export default function PetDetailPage() {
useEffect(() => {
if (!id) return;
- setLoading(true);
- setError(null);
fetch(`${API_BASE}/api/v1/pets/${id}`)
.then((res) => {
diff --git a/web/app/adopt/page.js b/web/app/adopt/page.js
index 430a1653..90293d8c 100644
--- a/web/app/adopt/page.js
+++ b/web/app/adopt/page.js
@@ -12,10 +12,8 @@ export default function AdoptPage() {
const [health, setHealth] = useState(null);
const [search, setSearch] = useState("");
const [query, setQuery] = useState("");
- const [page, setPage] = useState(0);
- const [totalPages, setTotalPages] = useState(0);
- const PAGE_SIZE = 12;
+ const PAGE_SIZE = 200;
useEffect(() => {
fetch(`${API_BASE}/api/v1/health`)
@@ -24,10 +22,7 @@ export default function AdoptPage() {
}, []);
useEffect(() => {
- setLoading(true);
- setError(null);
-
- const params = new URLSearchParams({ page, size: PAGE_SIZE, sort: "id,asc" });
+ const params = new URLSearchParams({ page: 0, size: PAGE_SIZE, sort: "petId,asc" });
if (query) params.set("q", query);
fetch(`${API_BASE}/api/v1/pets?${params}`)
@@ -37,15 +32,15 @@ export default function AdoptPage() {
})
.then((data) => {
setPets(data.content ?? []);
- setTotalPages(data.totalPages ?? 0);
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
- }, [page, query]);
+ }, [query]);
function handleSearch(e) {
e.preventDefault();
- setPage(0);
+ setLoading(true);
+ setError(null);
setQuery(search.trim());
}
@@ -72,7 +67,7 @@ export default function AdoptPage() {
@@ -125,25 +120,6 @@ export default function AdoptPage() {
)}
- {!loading && totalPages > 1 && (
-
+
Appointment Booking
-
{selectedService.serviceDesc}
+
Web appointment booking is currently available for customer accounts only.
+
Admin and staff accounts can still review appointment activity below.
- )}
-
-
- Date
-
-
- {storeId && serviceId && appointmentDate && (
-
-
Available Time Slots
- {loadingSlots ? (
-
Checking availability...
- ) : availableSlots.length === 0 ? (
-
No available slots for this date. Please try another date.
- ) : (
-
- {availableSlots.map((slot) => (
-
- ))}
-
- )}
-
- )}
-
- {serviceId && (
-
-
{petSectionLabel}
- {petsToShow.length === 0 ? (
-
{noPetsMessage}
- ) : isAdoptionService ? (
-
- {petsToShow.map((p) => (
-
- ))}
-
- ) : (
-
- {petsToShow.map((p) => (
-
- ))}
-
- )}
-
- )}
-
-
-
+ )}
-
Your Appointments
+
{canBookAppointments ? "Your Appointments" : "Appointments"}
{loadingAppointments ? (
Loading appointments...
) : appointments.length === 0 ? (
@@ -637,4 +662,8 @@ export default function AppointmentsPage() {
);
-}
\ No newline at end of file
+}
+
+export default dynamic(() => Promise.resolve(AppointmentsPage), {
+ ssr: false,
+});
diff --git a/web/app/contact/page.js b/web/app/contact/page.js
new file mode 100644
index 00000000..85fba175
--- /dev/null
+++ b/web/app/contact/page.js
@@ -0,0 +1,73 @@
+const LOCATIONS = [
+ {
+ name: "Downtown Branch",
+ address: "123 Main St",
+ phone: "(123) 456-7890",
+ email: "downtown@petshop.com",
+ },
+ {
+ name: "North Branch",
+ address: "456 North Ave",
+ phone: "(987) 654-3210",
+ email: "north@petshop.com",
+ },
+ {
+ name: "West Side Store",
+ address: "789 West Blvd",
+ phone: "(555) 123-4567",
+ email: "westside@petshop.com",
+ },
+];
+
+const PERSONNEL = [
+ { name: "John Doe", role: "Store Manager" },
+ { name: "Sara Smith", role: "Staff" },
+ { name: "Michael Johnson", role: "Grooming Team" },
+];
+
+export default function ContactPage() {
+ return (
+
+
+ Contact Us
+ Reach the team, find a location, or connect with store personnel.
+
+
+
+
+
+
General Contact
+
Email: support@petshop.com
+
Phone: (000) 000-0000
+
Hours: Mon–Sat, 9:00 AM – 6:00 PM
+
+
+
+
Store Locations
+
+ {LOCATIONS.map((location) => (
+
+ {location.name}
+ {location.address}
+ {location.phone}
+ {location.email}
+
+ ))}
+
+
+
+
+
Store Personnel
+
+ {PERSONNEL.map((person) => (
+
+ {person.name}
+ {person.role}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/web/app/globals.css b/web/app/globals.css
index 500ccbb0..da8ce03b 100644
--- a/web/app/globals.css
+++ b/web/app/globals.css
@@ -617,6 +617,74 @@ body {
min-height: 100vh;
}
+.info-page {
+ min-height: 100vh;
+ background: linear-gradient(to bottom, #f9f9f9, #ffffff);
+}
+
+.info-hero {
+ text-align: center;
+ padding: 4rem 2rem 3rem;
+}
+
+.info-title {
+ font-size: 3rem;
+ color: #333;
+ margin-bottom: 1rem;
+ font-weight: 700;
+}
+
+.info-subtitle {
+ font-size: 1.25rem;
+ color: #666;
+ margin-bottom: 1.5rem;
+}
+
+.info-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 2rem 4rem;
+ display: grid;
+ gap: 1.5rem;
+}
+
+.info-card {
+ background: white;
+ border-radius: 16px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+ padding: 1.5rem;
+}
+
+.info-card h2 {
+ margin-top: 0;
+ margin-bottom: 1rem;
+ color: #222;
+}
+
+.info-list {
+ margin: 0;
+ padding-left: 1.2rem;
+ display: grid;
+ gap: 0.5rem;
+}
+
+.info-card-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ gap: 1rem;
+}
+
+.info-mini-card {
+ background: #fff8ee;
+ border-radius: 12px;
+ padding: 1rem;
+}
+
+.info-mini-card h3 {
+ margin-top: 0;
+ margin-bottom: 0.5rem;
+}
+
.products-hero {
text-align: center;
padding: 4rem 2rem 3rem;
@@ -1698,4 +1766,4 @@ body {
.profile-pet-cancel-btn:hover {
border-color: #999;
color: #333;
-}
\ No newline at end of file
+}
diff --git a/web/app/login/page.js b/web/app/login/page.js
index 32c05c52..dcc78d02 100644
--- a/web/app/login/page.js
+++ b/web/app/login/page.js
@@ -1,5 +1,6 @@
"use client";
+import Link from "next/link";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/context/AuthContext";
@@ -64,10 +65,10 @@ export default function LoginPage() {
{loading ? "Logging in…" : "Log In"}
-
+
Don't have an account?{" "}
- Register here
+ Register here
diff --git a/web/app/page.js b/web/app/page.js
index 4819bd7d..91f71946 100644
--- a/web/app/page.js
+++ b/web/app/page.js
@@ -4,15 +4,21 @@ import Image from "next/image";
import Link from "next/link";
import { useState, useEffect } from "react";
-export default function Home() {
- //Slideshow images array
- const slideshowImages = [
- {src: "/images/home/slideshow/pet1.jpg", alt: "Happy pets"},
- {src: "/images/home/slideshow/pet2.jpg", alt: "Pet supplies"},
- {src: "/images/home/slideshow/pet3.jpg", alt: "Pet grooming"},
- {src: "/images/home/slideshow/pet4.jpg", alt: "Pet food"},
- ];
+const slideshowImages = [
+ {id: "slide-1", src: "/images/home/slideshow/pet1.jpg", alt: "Happy pets"},
+ {id: "slide-2", src: "/images/home/slideshow/pet2.jpg", alt: "Pet supplies"},
+ {id: "slide-3", src: "/images/home/slideshow/pet3.jpg", alt: "Pet grooming"},
+ {id: "slide-4", src: "/images/home/slideshow/pet4.jpg", alt: "Pet food"},
+];
+const navImages = [
+ {id: "nav-adopt", src: "/images/home/navimages/adopt.jpg", alt: "Adopt a Pet", link: "/adopt", title: "Adopt a Pet"},
+ {id: "nav-products", src: "/images/home/navimages/store.jpg", alt: "Online Store", link: "/products", title: "Online Store"},
+ {id: "nav-appointments", src: "/images/home/navimages/appointments.jpg", alt: "Appointments", link: "/appointments", title: "Appointments"},
+ {id: "nav-about", src: "/images/home/navimages/about.jpg", alt: "About Us", link: "/about", title: "About Us"},
+];
+
+export default function Home() {
const [currentSlide, setCurrentSlide] = useState(0);
//Auto-advance slideshow
@@ -21,15 +27,7 @@ export default function Home() {
const timer = setInterval(() => {setCurrentSlide((prev) => (prev + 1) % slideshowImages.length);}, 7500);
return () => clearInterval(timer);
- }, [slideshowImages.length]);
-
- //Hyperlinks to other pages
- const navImages = [
- {src: "/images/home/navimages/adopt.jpg", alt: "Adopt a Pet", link: "/adopt", title: "Adopt a Pet"},
- {src: "/images/home/navimages/store.jpg", alt: "Online Store", link: "/store", title: "Online Store"},
- {src: "/images/home/navimages/appointments.jpg", alt: "Appointments", link: "/appointments", title: "Appointments"},
- {src: "/images/home/navimages/about.jpg", alt: "About Us", link: "/about", title: "About Us"},
- ];
+ }, []);
return (
@@ -37,7 +35,7 @@ export default function Home() {
{slideshowImages.map((image, index) => (
{navImages.map((item, index) => (
-
+
);
-}
\ No newline at end of file
+}
diff --git a/web/app/products/[id]/page.js b/web/app/products/[id]/page.js
index 833cbd24..47a3059b 100644
--- a/web/app/products/[id]/page.js
+++ b/web/app/products/[id]/page.js
@@ -17,9 +17,6 @@ export default function ProductDetailPage() {
if (!id) {
return;
}
-
- setLoading(true);
- setError(null);
fetch(`${API_BASE}/api/v1/products/${id}`)
.then((res) => {
diff --git a/web/app/products/page.js b/web/app/products/page.js
index f44475f1..b3416326 100644
--- a/web/app/products/page.js
+++ b/web/app/products/page.js
@@ -11,16 +11,11 @@ export default function ProductsPage() {
const [error, setError] = useState(null);
const [search, setSearch] = useState("");
const [query, setQuery] = useState("");
- const [page, setPage] = useState(0);
- const [totalPages, setTotalPages] = useState(0);
- const PAGE_SIZE = 12;
+ const PAGE_SIZE = 200;
useEffect(() => {
- setLoading(true);
- setError(null);
-
- const params = new URLSearchParams({ page, size: PAGE_SIZE, sort: "prodId,asc" });
+ const params = new URLSearchParams({ page: 0, size: PAGE_SIZE, sort: "prodId,asc" });
if (query) {
params.set("q", query);
}
@@ -35,15 +30,15 @@ export default function ProductsPage() {
})
.then((data) => {
setProducts(data.content ?? []);
- setTotalPages(data.totalPages ?? 0);
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
- }, [page, query]);
+ }, [query]);
function handleSearch(e) {
e.preventDefault();
- setPage(0);
+ setLoading(true);
+ setError(null);
setQuery(search.trim());
}
@@ -70,7 +65,7 @@ export default function ProductsPage() {
@@ -108,25 +103,6 @@ export default function ProductsPage() {
)}
- {!loading && totalPages > 1 && (
-
-
- Page {page + 1} of {totalPages}
-
-
- )}
);
diff --git a/web/app/register/page.js b/web/app/register/page.js
index 20dcd2c1..eb9de480 100644
--- a/web/app/register/page.js
+++ b/web/app/register/page.js
@@ -1,5 +1,6 @@
"use client";
+import Link from "next/link";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/context/AuthContext";
@@ -140,10 +141,10 @@ export default function RegisterPage() {
{loading ? "Creating account…" : "Register"}
-
+
Already have an account?{" "}
- Log in here
+ Log in here
diff --git a/web/components/Navigation.js b/web/components/Navigation.js
index cfd17924..3259c1d1 100644
--- a/web/components/Navigation.js
+++ b/web/components/Navigation.js
@@ -1,6 +1,7 @@
"use client";
import Image from "next/image";
+import Link from "next/link";
import { useRouter } from "next/navigation";
import { useAuth } from "@/context/AuthContext";
@@ -23,31 +24,31 @@ export default function DisplayNav() {
id="logo"/>
);
-}
\ No newline at end of file
+}