"use client"; import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { CATEGORIES } from "@/data/gunbuilderParts"; import type { CategoryId } from "@/types/gunbuilder"; type GunbuilderProductFromApi = { id: number; uuid: string; slug: string; name: string; brandName: string; platform: string; partRole: string; price: number | null; mainImageUrl: string | null; buyUrl: string | null; }; const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080"; export default function PartDetailPage() { const params = useParams(); const categoryId = params.categoryId as CategoryId; const partId = params.partId as string; // this is the UUID we passed in the link const [product, setProduct] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const category = useMemo( () => CATEGORIES.find((c) => c.id === categoryId), [categoryId], ); useEffect(() => { if (!partId) return; const controller = new AbortController(); async function fetchProduct() { try { setLoading(true); setError(null); // For now, pull the full AR-15 list and find by UUID. // We can optimize with a dedicated /api/products/gunbuilder/{uuid} later. const url = `${API_BASE_URL}/api/products/gunbuilder?platform=AR-15`; const res = await fetch(url, { signal: controller.signal }); if (!res.ok) { throw new Error(`Failed to load product (${res.status})`); } const data: GunbuilderProductFromApi[] = await res.json(); const found = data.find((p) => p.uuid === partId) ?? null; if (!found) { setError("Product not found"); } setProduct(found); } catch (err: any) { if (err.name === "AbortError") return; setError(err.message ?? "Failed to load product"); } finally { setLoading(false); } } fetchProduct(); return () => controller.abort(); }, [partId]); if (!category) { return (

Category Not Found

Return to Gunbuilder
); } return (
{/* Breadcrumbs */} {loading ? (

Loading product…

) : error || !product ? (

Product Unavailable

{error ?? "We couldn’t find this product."}

Back to {category.name} parts
) : (
{/* Left: image + meta */}
{product.mainImageUrl && (
{/* eslint-disable-next-line @next/next/no-img-element */} {product.name}
)}
{product.brandName}

{product.name}

Platform: {product.platform}

Role: {product.partRole}

{/* Right: pricing + actions */}
)}
); }