diff --git a/estore/src/app/api/bouquet-items/route.ts b/estore/src/app/api/bouquet-items/route.ts new file mode 100644 index 0000000..fe02c1a --- /dev/null +++ b/estore/src/app/api/bouquet-items/route.ts @@ -0,0 +1,23 @@ +import { NextResponse } from 'next/server' +import { getSquareCatalog } from '@/lib/square' + +export const dynamic = 'force-dynamic' + +/** + * GET /api/bouquet-items + * Returns catalog items in the Square "Build" category, bypassing the + * Online-category filter so bouquet components don't need to be listed + * items in the main storefront. + */ +export async function GET() { + try { + const items = await getSquareCatalog({ filterCategory: 'build' }) + return NextResponse.json({ items }, { + headers: { 'Cache-Control': 'public, max-age=30, stale-while-revalidate=60' }, + }) + } catch (err: unknown) { + const msg = err instanceof Error ? err.message : String(err) + console.error('[bouquet-items] error:', msg) + return NextResponse.json({ items: [] }, { status: 500 }) + } +} diff --git a/estore/src/components/BouquetPicker.tsx b/estore/src/components/BouquetPicker.tsx index 5202f19..34f2f45 100644 --- a/estore/src/components/BouquetPicker.tsx +++ b/estore/src/components/BouquetPicker.tsx @@ -63,22 +63,13 @@ export default function BouquetPicker({ product, onClose }: Props) { useEffect(() => { Promise.all([ - fetch(BASE + '/api/catalog').then((r) => r.ok ? r.json() : { items: [] }), + fetch(BASE + '/api/bouquet-items').then((r) => r.ok ? r.json() : { items: [] }), fetch(BASE + '/colors.json').then((r) => r.ok ? r.json() : []), ]).then(([{ items }, families]: [{ items: CatalogItem[] }, ColorFamily[]]) => { - // Log all unique category slugs so we can verify "build" is present - const allSlugs = Array.from(new Set((items as CatalogItem[]).flatMap((i) => i.categories ?? [i.category]))).sort() - console.log('[BouquetPicker] category slugs in catalog:', allSlugs) - setDebugSlugs(allSlugs) - - const inBuild = (item: CatalogItem) => - (item.categories ?? []).includes('build') || item.category === 'build' - - // Everything in the Build category — non-showColors items get quantity pickers, - // showColors items (e.g. the 11" latex) get the color picker treatment - const mylars = items.filter((i) => inBuild(i) && !i.showColors) - const latex = items.filter((i) => inBuild(i) && i.showColors) - console.log(`[BouquetPicker] found ${mylars.length} mylar items, ${latex.length} latex items in "build" category`) + // /api/bouquet-items already filters by the Build category server-side + const mylars = (items as CatalogItem[]).filter((i) => !i.showColors) + const latex = (items as CatalogItem[]).filter((i) => i.showColors) + setDebugSlugs([`${(items as CatalogItem[]).length} items fetched (${mylars.length} mylar, ${latex.length} latex)`]) setBuildItems([...mylars, ...latex]) setColorFamilies(families) diff --git a/estore/src/lib/square.ts b/estore/src/lib/square.ts index 2463ffc..8ff73e4 100644 --- a/estore/src/lib/square.ts +++ b/estore/src/lib/square.ts @@ -26,7 +26,12 @@ function getCatalogClient() { return new Client({ accessToken: token, environment: env }) } -export async function getSquareCatalog(): Promise { +/** + * When filterCategory is supplied, the Online-category filter is skipped and only + * items belonging to the named category (case-insensitive) are returned. + */ +export async function getSquareCatalog(options: { filterCategory?: string } = {}): Promise { + const { filterCategory } = options const client = getCatalogClient() // Fetch all pages (Square paginates listCatalog) @@ -88,14 +93,25 @@ export async function getSquareCatalog(): Promise { if (c.id && c.categoryData?.name) categoryNameMap.set(c.id, c.categoryData.name) }) + // Resolve the target category ID when filtering by a specific category name + const filterCategoryId = filterCategory + ? objects.find( + (o) => o.type === 'CATEGORY' && o.categoryData?.name?.toLowerCase() === filterCategory.toLowerCase() + )?.id + : undefined + const items = objects .filter((o) => o.type === 'ITEM') - .filter((o) => - // If an "online" category exists in Square, only show items tagged with it. - // If the category doesn't exist in this account, show all items. - !onlineCategoryId || - (o.itemData?.categories ?? []).some((c: { id?: string }) => c.id === onlineCategoryId) - ) + .filter((o) => { + const cats: { id?: string }[] = o.itemData?.categories ?? [] + // When a specific category is requested, skip the Online filter entirely + // and instead only keep items that belong to that category. + if (filterCategoryId) { + return cats.some((c) => c.id === filterCategoryId) + } + // Normal storefront path: apply the Online filter. + return !onlineCategoryId || cats.some((c) => c.id === onlineCategoryId) + }) .map((item) => { const data = item.itemData!