diff --git a/src/hooks/useMedusaProducts.ts b/src/hooks/useMedusaProducts.ts new file mode 100644 index 0000000..7432807 --- /dev/null +++ b/src/hooks/useMedusaProducts.ts @@ -0,0 +1,62 @@ +'use client' + +import { useState, useEffect } from 'react' + +export interface MedusaProductCategory { + id: string + name: string + handle: string +} + +export interface MedusaProduct { + id: string + title: string + description?: string + thumbnail?: string + // variants is optional — Medusa API may omit it when fields param is not set + variants?: Array<{ id: string; prices: Array<{ amount: number; currency_code: string }> }> + images?: Array<{ url: string }> + tags?: Array<{ value: string }> + created_at?: string + categories?: MedusaProductCategory[] +} + +interface UseMedusaProductsResult { + products: MedusaProduct[] + loading: boolean + isLoading: boolean // alias for loading — both work + error: string | null +} + +type UseMedusaProductsOptions = number | { limit?: number; categoryId?: string } + +// Accepts either a plain number or an options object — both call signatures are valid: +// useMedusaProducts(4) +// useMedusaProducts({ limit: 4, categoryId: 'cat_123' }) +export function useMedusaProducts(options: UseMedusaProductsOptions = 12): UseMedusaProductsResult { + // Extract scalars so useEffect deps are stable primitives, not object references. + const limit = typeof options === 'number' ? options : (options.limit ?? 12) + const categoryId = typeof options === 'number' ? undefined : options.categoryId + + const [products, setProducts] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + let controller = new AbortController() + const fetchProducts = () => { + controller = new AbortController() + const params = new URLSearchParams({ limit: String(limit) }) + if (categoryId) params.set('categoryId', categoryId) + fetch(`/api/medusa/products?${params}`, { signal: controller.signal }) + .then(res => res.ok ? res.json() : Promise.reject(res.status)) + .then(data => { setProducts(data.products ?? []); setLoading(false) }) + .catch(err => { if (err?.name !== 'AbortError') { setError(String(err)); setLoading(false) } }) + } + fetchProducts() + const interval = setInterval(fetchProducts, 30000) + return () => { clearInterval(interval); controller.abort() } + }, [limit, categoryId]) + + return { products, loading, isLoading: loading, error } +}