feat(product-list): implement pagination and update items to use paginated response
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
[class.product-list--row]="layout() === 'row'"
|
||||
[class.product-list--column]="layout() !== 'row'"
|
||||
>
|
||||
@for (item of items(); track item.id; let index = $index) {
|
||||
@for (item of items().data; track item.id; let index = $index) {
|
||||
<div class="product-list__item">
|
||||
@switch (layout()) {
|
||||
@case ('row') {
|
||||
@@ -38,3 +38,14 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (items().meta.last_page > 1) {
|
||||
<div class="product-list__paginator d-flex justify-content-center">
|
||||
<app-paginator
|
||||
[page]="items().meta.current_page"
|
||||
[totalPages]="items().meta.last_page"
|
||||
[disabled]="loading()"
|
||||
(pageChange)="pageChange.emit($event)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -25,3 +25,7 @@
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.product-list__paginator {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { TestBed, getTestBed } from '@angular/core/testing';
|
||||
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
|
||||
import { afterEach, beforeAll, describe, expect, it } from 'vitest';
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { ApiPaginatedResponse } from '../../../core/services/api-paginated-response.interface';
|
||||
import { ProductListComponent, ProductListItem, ProductListLayout } from './product-list.component';
|
||||
|
||||
describe('ProductListComponent', () => {
|
||||
@@ -38,12 +39,34 @@ describe('ProductListComponent', () => {
|
||||
await TestBed.configureTestingModule({ imports: [ProductListComponent] }).compileComponents();
|
||||
const fixture = TestBed.createComponent(ProductListComponent);
|
||||
fixture.componentRef.setInput('layout', layout);
|
||||
fixture.componentRef.setInput('items', items);
|
||||
fixture.componentRef.setInput('items', paginatedItems());
|
||||
fixture.detectChanges();
|
||||
|
||||
return fixture;
|
||||
}
|
||||
|
||||
function paginatedItems(currentPage = 1, lastPage = 2): ApiPaginatedResponse<ProductListItem[]> {
|
||||
return {
|
||||
data: items,
|
||||
meta: {
|
||||
current_page: currentPage,
|
||||
from: 1,
|
||||
last_page: lastPage,
|
||||
links: [],
|
||||
path: '/catalog/featured-groups/1/items',
|
||||
per_page: 12,
|
||||
to: 2,
|
||||
total: 13,
|
||||
},
|
||||
links: {
|
||||
first: '/catalog/featured-groups/1/items?page=1',
|
||||
last: '/catalog/featured-groups/1/items?page=2',
|
||||
prev: null,
|
||||
next: '/catalog/featured-groups/1/items?page=2',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
it('renders every row product at full available width', async () => {
|
||||
const fixture = await render('row');
|
||||
const element = fixture.nativeElement as HTMLElement;
|
||||
@@ -70,4 +93,17 @@ describe('ProductListComponent', () => {
|
||||
),
|
||||
).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('renders pagination and emits the requested page', async () => {
|
||||
const fixture = await render('row');
|
||||
const pageChangeSpy = vi.fn();
|
||||
fixture.componentInstance.pageChange.subscribe(pageChangeSpy);
|
||||
|
||||
const nextButton = (fixture.nativeElement as HTMLElement).querySelector(
|
||||
'[data-testid="paginator-next"]',
|
||||
) as HTMLButtonElement;
|
||||
nextButton.click();
|
||||
|
||||
expect(pageChangeSpy).toHaveBeenCalledWith(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';
|
||||
|
||||
import { ApiPaginatedResponse } from '../../../core/services/api-paginated-response.interface';
|
||||
import { PaginatorComponent } from '../paginator/paginator.component';
|
||||
import { ProductColumnWithImageComponent } from '../product-column-with-image/product-column-with-image.component';
|
||||
import {
|
||||
ProductRowCardComponent,
|
||||
@@ -35,6 +37,7 @@ export interface ProductListCartEvent {
|
||||
selector: 'app-product-list',
|
||||
imports: [
|
||||
ProductColumnWithImageComponent,
|
||||
PaginatorComponent,
|
||||
ProductRowCardComponent,
|
||||
ProductVerticalWithCartCardComponent,
|
||||
],
|
||||
@@ -44,10 +47,12 @@ export interface ProductListCartEvent {
|
||||
})
|
||||
export class ProductListComponent {
|
||||
readonly layout = input.required<ProductListLayout>();
|
||||
readonly items = input.required<readonly ProductListItem[]>();
|
||||
readonly items = input.required<ApiPaginatedResponse<ProductListItem[]>>();
|
||||
readonly loading = input(false);
|
||||
|
||||
readonly buy = output<ProductListItem>();
|
||||
readonly addToCart = output<ProductListCartEvent>();
|
||||
readonly pageChange = output<number>();
|
||||
|
||||
protected price(item: ProductListItem): number {
|
||||
const price = Number(item.precio);
|
||||
|
||||
Reference in New Issue
Block a user