import 'server-only'; export interface ProductImageDto { id: string; productId: string; variantId: string | null; url: string; altText: string; position: number; role: 'main' | 'gallery'; createdAt: string; updatedAt: string; } export interface CategoryDto { id: string; parentId: string | null; name: string; slug: string; url: string; seoTitle: string | null; seoDescription: string | null; emoji?: string | null; color?: string | null; createdAt: string; updatedAt: string; } export interface CategoryTreeNodeDto extends CategoryDto { children: CategoryTreeNodeDto[]; } export interface BrandDto { id: string; name: string; slug: string; url: string; seoTitle: string | null; seoDescription: string | null; createdAt: string; updatedAt: string; } export interface ProductSummaryDto { id: string; name: string; slug: string; url: string; images?: ProductImageDto[]; description: string | null; state: 'draft' | 'active' | 'archived'; seoTitle: string | null; seoDescription: string | null; categoryIds: string[]; brandId: string | null; createdAt: string; updatedAt: string; } interface ProductSearchResponse { items: ProductSummaryDto[]; } interface CategoryTreeResponse { items: CategoryTreeNodeDto[]; } interface BrandListResponse { items: BrandDto[]; } export interface SearchProductsInput { q?: string; brandSlug?: string; categorySlug?: string; limit?: number; offset?: number; } const DEFAULT_API_BASE_URL = 'http://localhost:3000'; function apiBaseUrl(): string { return ( process.env.API_BASE_URL ?? process.env.NEXT_PUBLIC_API_BASE_URL ?? DEFAULT_API_BASE_URL ).replace(/\/$/, ''); } function toQueryString(input: SearchProductsInput): string { const params = new URLSearchParams(); if (input.q !== undefined && input.q.trim() !== '') params.set('q', input.q.trim()); if (input.brandSlug !== undefined && input.brandSlug.trim() !== '') { params.set('brandSlug', input.brandSlug.trim()); } if (input.categorySlug !== undefined && input.categorySlug.trim() !== '') { params.set('categorySlug', input.categorySlug.trim()); } if (input.limit !== undefined) params.set('limit', String(input.limit)); if (input.offset !== undefined) params.set('offset', String(input.offset)); const query = params.toString(); return query === '' ? '' : `?${query}`; } async function fetchJson(path: string): Promise { const response = await fetch(`${apiBaseUrl()}${path}`, { headers: { accept: 'application/json' }, next: { revalidate: 60 }, }); if (!response.ok) { throw new Error(`Public API request failed with status ${response.status}`); } return (await response.json()) as T; } export async function searchProducts( input: SearchProductsInput = {}, ): Promise { const payload = await fetchJson(`/products/search${toQueryString(input)}`); return payload.items; } export async function getProductBySlug(slug: string): Promise { return fetchJson(`/productos/${encodeURIComponent(slug)}`); } export async function getCategoryBySlug(slug: string): Promise { return fetchJson(`/categoria/${encodeURIComponent(slug)}`); } export async function listCategoryTree(): Promise { const payload = await fetchJson('/categories/tree'); return payload.items; } export async function getBrandBySlug(slug: string): Promise { return fetchJson(`/marca/${encodeURIComponent(slug)}`); } export async function listBrands(): Promise { const payload = await fetchJson('/brands'); return payload.items; }