Files
apps-registry/workloads/ecommerce/lib/headless/providers/mock.ts
devopsandClaude Sonnet 5 8742ce714c
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (pull_request) Successful in 35s
Build and Push Frontend / Construir y Subir Imagen (pull_request) Skipped
fix(ecommerce): nav y tiles data-driven contra la jerarquia real de categorias
Sub-fase 2 de Etapa 2 (ADR 0005 seccion 6). Navbar y CategoryTiles usaban
arrays hardcodeados (Figuras/Peluches/Mochilas/Marvel) que ya no coinciden
con los nombres reales de categoria en Medusa desde que se elimino
legacyProductMeta (PR #29) -- todos esos links de navegacion quedaron
rotos silenciosamente (0 productos al filtrar).

- lib/headless: nuevo tipo Category + metodo getCategories() en
  CatalogProvider (medusa via /store/product-categories, mock deriva de
  su catalogo plano, shopify sin implementar como el resto de sus metodos).
- Navbar: arbol real de categorias (6 raices/21 nodos), dropdown de
  hijos por raiz en desktop, lista anidada en el sheet movil. Colecciones
  del sheet ahora se derivan de los productos reales en vez de un array
  hardcodeado con 2 nombres obsoletos (Marvel/Frozen vs. los reales
  Universo Marvel/Reino de Frozen).
- CategoryTiles: tiles de home por categoria raiz real; imagen solo donde
  ya existe asset, gradiente honesto donde no (no hay fotografia para las
  6 raices todavia, deuda explicita del ADR).
- catalog-client/catalog page: cuando el query param `category` es una
  raiz con hijos, se expande a los nombres reales de sus hijos para que
  el filtro (igualdad exacta de producto.category) siga funcionando --
  sin esto, tiles/nav apuntando a una raiz mostrarian 0 productos porque
  ningun producto tiene la raiz asignada directamente.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013dunTcReWMKhWgCPkvAVHD
2026-08-24 21:21:18 -05:00

55 lines
2.1 KiB
TypeScript

import catalog from "@/data/products.json";
import type { CatalogProvider, Category, Product, ProductFilters } from "@/lib/headless/types";
const products = catalog satisfies Product[];
function normalize(value: string): string {
return value.toLocaleLowerCase("es").normalize("NFD").replace(/[\u0300-\u036f]/g, "");
}
function matches(product: Product, filters: ProductFilters): boolean {
if (filters.category && filters.category !== "Todos" && product.category !== filters.category) return false;
if (filters.collection && product.collection !== filters.collection) return false;
if (filters.brand && product.brand !== filters.brand) return false;
if (filters.ageRange && product.ageRange !== filters.ageRange) return false;
if (filters.minPrice !== undefined && product.price !== null && product.price < filters.minPrice) return false;
if (filters.maxPrice !== undefined && product.price !== null && product.price > filters.maxPrice) return false;
if (filters.query) {
const query = normalize(filters.query);
const haystack = normalize([
product.name,
product.description,
product.category,
product.collection,
product.brand,
...product.tags,
].join(" "));
if (!haystack.includes(query)) return false;
}
return true;
}
export const mockCatalogProvider: CatalogProvider = {
async getProducts(filters = {}) {
return products.filter((product) => matches(product, filters));
},
async getProductBySlug(slug) {
return products.find((product) => product.slug === slug) ?? null;
},
async searchProducts(query, limit = 6) {
return products.filter((product) => matches(product, { query })).slice(0, limit);
},
async getCategories(): Promise<Category[]> {
// El catalogo mock no tiene jerarquia real (a diferencia de Medusa) --
// se devuelve una lista plana de las categorias que ya usan los
// productos mock, todas sin padre.
const names = [...new Set(products.map((product) => product.category))].filter(Boolean);
return names.map((name) => ({
id: name,
name,
handle: normalize(name).replace(/\s+/g, "-"),
parentId: null,
}));
},
};