From 82935303babb310b2e931cc111972ed74714685f Mon Sep 17 00:00:00 2001 From: augmentedpotato Date: Thu, 2 Apr 2026 08:54:24 -0600 Subject: [PATCH] Fix web routing --- web/app/about/page.js | 37 ++++ web/app/adopt/[id]/page.js | 2 - web/app/adopt/page.js | 36 +--- web/app/appointments/page.js | 329 ++++++++++++++++++---------------- web/app/contact/page.js | 73 ++++++++ web/app/globals.css | 70 +++++++- web/app/login/page.js | 5 +- web/app/page.js | 38 ++-- web/app/products/[id]/page.js | 3 - web/app/products/page.js | 36 +--- web/app/register/page.js | 5 +- web/components/Navigation.js | 25 +-- 12 files changed, 407 insertions(+), 252 deletions(-) create mode 100644 web/app/about/page.js create mode 100644 web/app/contact/page.js 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 && ( -
- - Page {page + 1} of {totalPages} - -
- )} ); diff --git a/web/app/appointments/page.js b/web/app/appointments/page.js index d3f7943e..bec8bd78 100644 --- a/web/app/appointments/page.js +++ b/web/app/appointments/page.js @@ -1,5 +1,6 @@ "use client"; +import dynamic from "next/dynamic"; import { useState, useEffect, useCallback, useRef } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { useAuth } from "@/context/AuthContext"; @@ -68,8 +69,12 @@ function DatePicker({ value, minDate, onChange }) { } const cells = []; - for (let i = 0; i < firstDay; i++) cells.push(null); - for (let d = 1; d <= daysInMonth; d++) cells.push(d); + for (let i = 0; i < firstDay; i++) { + cells.push({ key: `empty-${viewYear}-${viewMonth}-${String(i)}`, day: null }); + } + for (let d = 1; d <= daysInMonth; d++) { + cells.push({ key: `day-${viewYear}-${viewMonth}-${String(d)}`, day: d }); + } const s = { widget: { @@ -160,12 +165,12 @@ function DatePicker({ value, minDate, onChange }) { {DAYS.map((d) => ( {d} ))} - {cells.map((day, i) => + {cells.map(({ key, day }) => day === null ? ( - + ) : ( + ))} + + )} + + )} + + {serviceId && ( +
+ {petSectionLabel} + {petsToShow.length === 0 ? ( +

{noPetsMessage}

+ ) : isAdoptionService ? ( +
+ {petsToShow.map((p) => ( + + ))} +
+ ) : ( +
+ {petsToShow.map((p) => ( + + ))} +
+ )} +
+ )} + + + + ) : ( +
+

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"/>
- Home - Adopt a Pet - Online Store - Schedule an Appointment - Contact Us - About Us + Home + Adopt a Pet + Online Store + Schedule an Appointment + Contact Us + About Us
{loading ? null : user ? ( <> - + Hello, {user.fullName || user.username} - - ) : ( <> - Log In - Register + Log In + Register )}
); -} \ No newline at end of file +}