From 4dd89442661b8294b54fb3c6e796404c39b2dcc4 Mon Sep 17 00:00:00 2001 From: Vula Builder Date: Sat, 1 Aug 2026 17:20:22 +0000 Subject: [PATCH] Deploy --- src/hooks/useFeaturedProducts.ts | 73 ++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/hooks/useFeaturedProducts.ts diff --git a/src/hooks/useFeaturedProducts.ts b/src/hooks/useFeaturedProducts.ts new file mode 100644 index 0000000..8f7603d --- /dev/null +++ b/src/hooks/useFeaturedProducts.ts @@ -0,0 +1,73 @@ +'use client' +import { useState, useEffect } from 'react' +import type { VulaProduct } from './useProducts' + +interface UseFeaturedProductsResult { + products: VulaProduct[] + loading: boolean + isLoading: boolean + error: string | null +} + +export function useFeaturedProducts(fallbackLimit = 8): UseFeaturedProductsResult { + const [products, setProducts] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + let cancelled = false + + async function load() { + try { + // Step 1: fetch curated IDs from Vula CMS + const cmsRes = await fetch('/api/content/featured_products', { cache: 'no-store' }) + let ids: string[] = [] + if (cmsRes.ok) { + const cmsData = await cmsRes.json() + const items: Array<{ data: { product_ids?: unknown } }> = cmsData.items ?? [] + const first = items[0]?.data?.product_ids + ids = Array.isArray(first) ? (first as string[]).filter(Boolean) : [] + } + + let fetched: VulaProduct[] = [] + if (ids.length > 0) { + // Step 2: hydrate from Vula Commerce by ID + const params = new URLSearchParams() + ids.forEach((id) => params.append('id[]', id)) + params.set('limit', String(ids.length)) + const res = await fetch(`/api/products?${params}`) + if (res.ok) { + const data = await res.json() + fetched = data.products ?? [] + } + } + + if (fetched.length === 0) { + // Step 3: fallback — latest products from Vula Commerce + const fallbackRes = await fetch(`/api/products?limit=${fallbackLimit}`) + if (fallbackRes.ok) { + const data = await fallbackRes.json() + fetched = data.products ?? [] + } + } + + if (!cancelled) { setProducts(fetched); setLoading(false) } + } catch (err) { + if (!cancelled) { setError(String(err)); setLoading(false) } + } + } + + load() + // Poll every 30 s + refetch on tab focus so Business Studio additions appear promptly. + const interval = setInterval(load, 30000) + const onVisible = () => { if (document.visibilityState === 'visible') load() } + document.addEventListener('visibilitychange', onVisible) + return () => { + cancelled = true + clearInterval(interval) + document.removeEventListener('visibilitychange', onVisible) + } + }, [fallbackLimit]) + + return { products, loading, isLoading: loading, error } +}