From 85a237f78feafd8d7204e7264d5022feca012b93 Mon Sep 17 00:00:00 2001 From: Steve Simonson <144349219+SteveSimonson@users.noreply.github.com> Date: Sun, 2 Aug 2026 18:08:02 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20restore=20full=20iBamboo=20catalog=20?= =?UTF-8?q?=E2=80=94=20merge=20flash,=20do=20not=20replace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flash-only SoT wiped the shop to ~12 SKUs. Layer live flash on top of the static house/BSR assortment again until Flash publish depth can safely own the full shelf. --- src/data/catalog.ts | 4 ++-- src/hooks/useFlashCatalog.ts | 31 ++++++++++++++++++------------- src/pages/Shop.tsx | 16 ++++++++-------- tests/flash-catalog.test.mjs | 25 +++++++++++++++++++------ 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/data/catalog.ts b/src/data/catalog.ts index 4eda6cc..9faf495 100644 --- a/src/data/catalog.ts +++ b/src/data/catalog.ts @@ -1,7 +1,7 @@ /** * iBamboo catalog helpers. - * Live assortment SoT is Flash Catalog (see useFlashCatalog). - * Static merge below is emergency fallback when flash is unreachable. + * Static house + BSR catalog is the bulk shelf. Flash layers on top when live + * (see useFlashCatalog merge) until Flash publish depth can own full assortment. */ export type { Category, Product, ProductSpec } from './types' export { products as curatedProducts } from './products' diff --git a/src/hooks/useFlashCatalog.ts b/src/hooks/useFlashCatalog.ts index 0e9e30c..4040a91 100644 --- a/src/hooks/useFlashCatalog.ts +++ b/src/hooks/useFlashCatalog.ts @@ -26,17 +26,22 @@ function finalizePool(list: Product[]): Product[] { return out } +/** + * Merge flash over static house catalog. + * Flash alone is still too thin (~12 SKUs) to own the full shop; until Flash + * publish depth is production-grade, keep static assortment and layer flash on top. + */ +function mergeFlashOverStatic(flash: Product[]): Product[] { + return finalizePool([...flash, ...shopProducts]) +} + export type FlashCatalogState = { - /** - * Active shop assortment. - * When source === 'flash', this is flash-only (control plane SoT). - * When source === 'static', emergency fallback (static BSR/curated). - */ + /** Full shop list: flash picks first, then full static catalog */ products: Product[] flashOnly: Product[] payload: FlashCatalogPayload | null loading: boolean - source: 'flash' | 'static' + source: 'flash' | 'static' | 'merged' error?: string generatedAt?: string weekOf?: string @@ -44,8 +49,8 @@ export type FlashCatalogState = { } /** - * Load site assortment from Flash Catalog (source of truth). - * Static catalog is emergency fallback only when flash is empty/unreachable. + * Load flash catalog and merge onto the static house/BSR assortment. + * Static is the bulk shelf; flash is live control-plane overlay (not a wipe). */ export function useFlashCatalog(siteId = 'ibamboo'): FlashCatalogState { const catalogBaseUrl = flashCatalogBaseUrl() @@ -89,14 +94,14 @@ export function useFlashCatalog(siteId = 'ibamboo'): FlashCatalogState { return useMemo(() => { const flashOnly = finalizePool(mapFlashProducts(payload)) + const staticPool = finalizePool(shopProducts) if (flashOnly.length > 0) { return { - // Assortment SoT: flash products only — do not merge static shelves - products: flashOnly, + products: mergeFlashOverStatic(flashOnly), flashOnly, payload, loading, - source: 'flash' as const, + source: 'merged' as const, error: undefined, generatedAt: payload?.generatedAt, weekOf: payload?.weekOf, @@ -104,12 +109,12 @@ export function useFlashCatalog(siteId = 'ibamboo'): FlashCatalogState { } } return { - products: finalizePool(shopProducts), + products: staticPool, flashOnly: [], payload: null, loading, source: 'static' as const, - error: error || (loading ? undefined : 'Using static emergency catalog'), + error: error || (loading ? undefined : undefined), weekOf: undefined, generatedAt: undefined, catalogBaseUrl, diff --git a/src/pages/Shop.tsx b/src/pages/Shop.tsx index 7ca00da..797347f 100644 --- a/src/pages/Shop.tsx +++ b/src/pages/Shop.tsx @@ -151,8 +151,8 @@ export function Shop() {
{limited - ? 'Assortment from the live flash catalog control plane — filters and schedule managed there; refresh anytime without a site redeploy.' - : 'Browse by room of the house, then buy on Amazon with secure checkout. Assortment is driven by the flash catalog.'} + ? 'This week’s limited options from the house edit and live flash refresh.' + : 'Browse by room of the house, then buy on Amazon with secure checkout.'}
{flash.loading ? 'Loading assortment…' - : flash.source === 'flash' - ? 'Live assortment' - : 'Emergency static catalog'} + : flash.source === 'merged' + ? 'Full collection · live flash layered' + : 'Full collection'}
{flash.loading ? '…' : `${pool.length} products`} + {!flash.loading && flash.flashOnly.length + ? ` · ${flash.flashOnly.length} live flash` + : ''} {!flash.loading && drop.weekOf ? ` · week of ${drop.weekOf}` : ''} {!flash.loading && until ? ` · rotates ${until}` : ''} - {!flash.loading && flash.error && flash.source === 'static' - ? ` · ${flash.error}` - : ''}