diff --git a/src/app/core/services/catalog/catalog.interface.ts b/src/app/core/services/catalog/catalog.interface.ts index 11693be..18977a2 100644 --- a/src/app/core/services/catalog/catalog.interface.ts +++ b/src/app/core/services/catalog/catalog.interface.ts @@ -65,6 +65,7 @@ export interface CatalogItemDetail { } export type CatalogProductLayout = 'row' | 'column_with_image' | 'column_with_cart'; +export type CatalogGroupLayout = 'paginated' | 'simple' | 'simple_vertical' | 'carousel'; export interface CatalogFeaturedItemVariant { id: number; @@ -82,10 +83,14 @@ export interface CatalogFeaturedItem { variants?: CatalogFeaturedItemVariant[]; } +export type CatalogFeaturedItems = + ApiPaginatedResponse | CatalogFeaturedItem[]; + export interface CatalogFeaturedGroup { id: number; title: string; layout: CatalogProductLayout; + group_layout: CatalogGroupLayout; group_order: number; - items: ApiPaginatedResponse; + items: CatalogFeaturedItems; } diff --git a/src/app/core/services/catalog/catalog.service.ts b/src/app/core/services/catalog/catalog.service.ts index 394de08..627f22b 100644 --- a/src/app/core/services/catalog/catalog.service.ts +++ b/src/app/core/services/catalog/catalog.service.ts @@ -8,7 +8,7 @@ import { ApiResponse } from '../api-response.interface'; import { TenantService } from '../tenant.service'; import { CatalogFeaturedGroup, - CatalogFeaturedItem, + CatalogFeaturedItems, CatalogItemDetail, Product, } from './catalog.interface'; @@ -39,8 +39,8 @@ export class CatalogService { getFeaturedGroupItems( featuredGroupId: number, params?: ApiPaginationQueryParams, - ): Observable> { - return this.http.get>( + ): Observable { + return this.http.get( `${this.tenantApiUrl}/catalog/featured-groups/${featuredGroupId}/items`, { params: this.buildHttpParams(params) }, ); diff --git a/src/app/features/store/pages/store-home-page/store-home-page.component.spec.ts b/src/app/features/store/pages/store-home-page/store-home-page.component.spec.ts index 968320f..b8c3dd4 100644 --- a/src/app/features/store/pages/store-home-page/store-home-page.component.spec.ts +++ b/src/app/features/store/pages/store-home-page/store-home-page.component.spec.ts @@ -56,6 +56,7 @@ function createCatalog( id: 7, title: 'Destacados', layout: 'column_with_image', + group_layout: 'paginated', group_order: 0, items: createItemsPage(items, currentPage, lastPage), }, diff --git a/src/app/features/store/pages/store-home-page/store-home-page.component.ts b/src/app/features/store/pages/store-home-page/store-home-page.component.ts index fa2a15f..4ddc3fa 100644 --- a/src/app/features/store/pages/store-home-page/store-home-page.component.ts +++ b/src/app/features/store/pages/store-home-page/store-home-page.component.ts @@ -53,8 +53,7 @@ export class StoreHomePageComponent implements OnInit, OnDestroy { ngOnInit(): void { const resolvedData = this.route.snapshot.data['catalogData'] as - | StoreHomeCatalogResolvedData - | undefined; + StoreHomeCatalogResolvedData | undefined; if (resolvedData) { this.applyResolvedData(resolvedData); @@ -78,6 +77,7 @@ export class StoreHomePageComponent implements OnInit, OnDestroy { if ( !group || + Array.isArray(group.items) || page < 1 || page === group.items.meta.current_page || this.isGroupLoading(groupId) @@ -112,18 +112,15 @@ export class StoreHomePageComponent implements OnInit, OnDestroy { } protected onAddToCart(event: ProductListCartEvent): void { - this.cartService - .addItem(event.product.id, event.variant ?? null, event.quantity) - .subscribe({ - next: (response) => { - this.toastService.success(response.message || 'Producto agregado al carrito'); - }, - error: (error: HttpErrorResponse) => { - const message = - error.error?.message || 'No se pudo agregar el producto al carrito.'; - this.toastService.danger(message); - }, - }); + this.cartService.addItem(event.product.id, event.variant ?? null, event.quantity).subscribe({ + next: (response) => { + this.toastService.success(response.message || 'Producto agregado al carrito'); + }, + error: (error: HttpErrorResponse) => { + const message = error.error?.message || 'No se pudo agregar el producto al carrito.'; + this.toastService.danger(message); + }, + }); } private loadCatalog(): void { diff --git a/src/app/shared/components/product-list/product-list.component.html b/src/app/shared/components/product-list/product-list.component.html index 86568b7..353de47 100644 --- a/src/app/shared/components/product-list/product-list.component.html +++ b/src/app/shared/components/product-list/product-list.component.html @@ -3,7 +3,7 @@ [class.product-list--row]="effectiveLayout() === 'row'" [class.product-list--column]="effectiveLayout() !== 'row'" > - @for (item of items().data; track item.id; let index = $index) { + @for (item of itemData(); track item.id; let index = $index) {
@switch (effectiveLayout()) { @case ('row') { @@ -39,13 +39,15 @@ }
-@if (items().meta.last_page > 1) { -
- -
+@if (pagination(); as paginatedItems) { + @if (paginatedItems.meta.last_page > 1) { +
+ +
+ } } diff --git a/src/app/shared/components/product-list/product-list.component.spec.ts b/src/app/shared/components/product-list/product-list.component.spec.ts index 25659ff..cb72da0 100644 --- a/src/app/shared/components/product-list/product-list.component.spec.ts +++ b/src/app/shared/components/product-list/product-list.component.spec.ts @@ -3,6 +3,7 @@ import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform- import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; import { ApiPaginatedResponse } from '../../../core/services/api-paginated-response.interface'; +import { CatalogFeaturedItems } from '../../../core/services/catalog/catalog.interface'; import { ProductListComponent, ProductListItem, ProductListLayout } from './product-list.component'; describe('ProductListComponent', () => { @@ -38,11 +39,14 @@ describe('ProductListComponent', () => { TestBed.resetTestingModule(); }); - async function render(layout: ProductListLayout) { + async function render( + layout: ProductListLayout, + productItems: CatalogFeaturedItems = paginatedItems(), + ) { await TestBed.configureTestingModule({ imports: [ProductListComponent] }).compileComponents(); const fixture = TestBed.createComponent(ProductListComponent); fixture.componentRef.setInput('layout', layout); - fixture.componentRef.setInput('items', paginatedItems()); + fixture.componentRef.setInput('items', productItems); fixture.detectChanges(); return fixture; @@ -128,4 +132,12 @@ describe('ProductListComponent', () => { expect(pageChangeSpy).toHaveBeenCalledWith(2); }); + + it('renders plain items without pagination', async () => { + const fixture = await render('row', items); + const element = fixture.nativeElement as HTMLElement; + + expect(element.querySelectorAll('app-product-row-card')).toHaveLength(2); + expect(element.querySelector('app-paginator')).toBeNull(); + }); }); diff --git a/src/app/shared/components/product-list/product-list.component.ts b/src/app/shared/components/product-list/product-list.component.ts index f231200..f267faa 100644 --- a/src/app/shared/components/product-list/product-list.component.ts +++ b/src/app/shared/components/product-list/product-list.component.ts @@ -10,9 +10,9 @@ import { signal, } from '@angular/core'; -import { ApiPaginatedResponse } from '../../../core/services/api-paginated-response.interface'; import { CatalogFeaturedItem, + CatalogFeaturedItems, CatalogFeaturedItemVariant, CatalogProductLayout, } from '../../../core/services/catalog/catalog.interface'; @@ -51,7 +51,7 @@ export class ProductListComponent { private readonly mobile = signal(false); readonly layout = input.required(); - readonly items = input.required>(); + readonly items = input.required(); readonly loading = input(false); readonly buy = output(); @@ -61,6 +61,16 @@ export class ProductListComponent { protected readonly effectiveLayout = computed(() => this.mobile() && this.layout() === 'row' ? 'column_with_cart' : this.layout(), ); + protected readonly itemData = computed(() => { + const items = this.items(); + + return Array.isArray(items) ? items : items.data; + }); + protected readonly pagination = computed(() => { + const items = this.items(); + + return Array.isArray(items) ? null : items; + }); constructor() { afterNextRender(() => {