"use client"; import { useEffect, useState } from "react"; import { useParams, useRouter } from "next/navigation"; import Link from "next/link"; import { getSpaceIdFromCookie, getCartKey } from "@/lib/spaces"; const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000/api"; interface ProductVariant { name: string; sku: string; provider: string; price: number; } interface Product { slug: string; name: string; description: string; category: string; product_type: string; tags: string[]; image_url: string; base_price: number; variants: ProductVariant[]; is_active: boolean; } export default function ProductPage() { const params = useParams(); const router = useRouter(); const slug = params.slug as string; const [product, setProduct] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [selectedVariant, setSelectedVariant] = useState(null); const [quantity, setQuantity] = useState(1); const [addingToCart, setAddingToCart] = useState(false); const [addedToCart, setAddedToCart] = useState(false); useEffect(() => { async function fetchProduct() { try { const res = await fetch(`${API_URL}/products/${slug}`); if (!res.ok) { if (res.status === 404) { setError("Product not found"); } else { setError("Failed to load product"); } return; } const data = await res.json(); setProduct(data); if (data.variants && data.variants.length > 0) { setSelectedVariant(data.variants[0]); } } catch { setError("Failed to load product"); } finally { setLoading(false); } } if (slug) { fetchProduct(); } }, [slug]); const getOrCreateCart = async (): Promise => { // Check for existing cart in localStorage let cartId = localStorage.getItem(getCartKey(getSpaceIdFromCookie())); if (cartId) { // Verify cart still exists try { const res = await fetch(`${API_URL}/cart/${cartId}`); if (res.ok) { return cartId; } } catch { // Cart doesn't exist, create new one } } // Create new cart try { const res = await fetch(`${API_URL}/cart`, { method: "POST", headers: { "Content-Type": "application/json" }, }); if (res.ok) { const data = await res.json(); cartId = data.id; localStorage.setItem(getCartKey(getSpaceIdFromCookie()), cartId!); return cartId; } } catch { return null; } return null; }; const handleAddToCart = async () => { if (!product || !selectedVariant) return; setAddingToCart(true); try { const cartId = await getOrCreateCart(); if (!cartId) { alert("Failed to create cart"); return; } const res = await fetch(`${API_URL}/cart/${cartId}/items`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ product_slug: product.slug, variant_sku: selectedVariant.sku, quantity: quantity, }), }); if (res.ok) { setAddedToCart(true); setTimeout(() => setAddedToCart(false), 3000); } else { const data = await res.json(); alert(data.detail || "Failed to add to cart"); } } catch { alert("Failed to add to cart"); } finally { setAddingToCart(false); } }; if (loading) { return (
); } if (error || !product) { return (

{error || "Product not found"}

Back to Products
); } return (
{/* Breadcrumb */}
{/* Product Image */}
{product.name}
{/* Product Details */}
{product.category} / {product.product_type}

{product.name}

{product.description}

${selectedVariant?.price.toFixed(2) || product.base_price.toFixed(2)}
{/* Variant Selection */} {product.variants && product.variants.length > 1 && (
{product.variants.map((variant) => ( ))}
)} {/* Quantity */}
{quantity}
{/* Add to Cart Button */} {/* View Cart Link */} {addedToCart && ( View Cart )} {/* Tags */} {product.tags && product.tags.length > 0 && (
Tags:
{product.tags.map((tag) => ( {tag} ))}
)}
); }