feat: implement store home page with product listing, pagination, and error handling
This commit is contained in:
@@ -31,6 +31,13 @@ function createTenantServiceStub(
|
|||||||
tenant: tenantState.asReadonly(),
|
tenant: tenantState.asReadonly(),
|
||||||
status: statusState.asReadonly(),
|
status: statusState.asReadonly(),
|
||||||
getTenant: () => tenantState(),
|
getTenant: () => tenantState(),
|
||||||
|
getTenantApiUrl: () => {
|
||||||
|
const tenantVal = tenantState();
|
||||||
|
if (!tenantVal) {
|
||||||
|
throw new Error('No se pudo resolver el tenant activo.');
|
||||||
|
}
|
||||||
|
return `http://localhost:8000/api/tenants/${tenantVal.codigo}`;
|
||||||
|
},
|
||||||
bootstrap: vi.fn().mockResolvedValue(undefined)
|
bootstrap: vi.fn().mockResolvedValue(undefined)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
export interface Product {
|
export interface Product {
|
||||||
id: number;
|
id: number;
|
||||||
tenant_codigo: string;
|
tenant_codigo: string;
|
||||||
categoria_id: number;
|
category_id: number;
|
||||||
|
brand_id: number | null;
|
||||||
slug: string;
|
slug: string;
|
||||||
nombre: string;
|
nombre: string;
|
||||||
descripcion?: string;
|
descripcion: string;
|
||||||
precio: string;
|
precio: string;
|
||||||
created_at?: string;
|
category: string;
|
||||||
updated_at?: string;
|
brand: string | null;
|
||||||
|
images: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,18 +38,28 @@ describe('StoreHomePageComponent', () => {
|
|||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
tenant_codigo: 'test',
|
tenant_codigo: 'test',
|
||||||
categoria_id: 10,
|
category_id: 10,
|
||||||
|
brand_id: null,
|
||||||
slug: 'auriculares-bluetooth',
|
slug: 'auriculares-bluetooth',
|
||||||
nombre: 'Auriculares Bluetooth',
|
nombre: 'Auriculares Bluetooth',
|
||||||
precio: '24999'
|
descripcion: 'Auriculares bluetooth de prueba',
|
||||||
|
precio: '24999',
|
||||||
|
category: 'Tecnología',
|
||||||
|
brand: null,
|
||||||
|
images: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
tenant_codigo: 'test',
|
tenant_codigo: 'test',
|
||||||
categoria_id: 11,
|
category_id: 11,
|
||||||
|
brand_id: null,
|
||||||
slug: 'teclado-mecanico',
|
slug: 'teclado-mecanico',
|
||||||
nombre: 'Teclado Mecanico',
|
nombre: 'Teclado Mecanico',
|
||||||
precio: '18999'
|
descripcion: 'Teclado mecánico de prueba',
|
||||||
|
precio: '18999',
|
||||||
|
category: 'Tecnología',
|
||||||
|
brand: null,
|
||||||
|
images: []
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -97,10 +107,15 @@ describe('StoreHomePageComponent', () => {
|
|||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
tenant_codigo: 'test',
|
tenant_codigo: 'test',
|
||||||
categoria_id: 12,
|
category_id: 12,
|
||||||
|
brand_id: null,
|
||||||
slug: 'mouse-gamer',
|
slug: 'mouse-gamer',
|
||||||
nombre: 'Mouse Gamer',
|
nombre: 'Mouse Gamer',
|
||||||
precio: '15999'
|
descripcion: 'Mouse gamer de prueba',
|
||||||
|
precio: '15999',
|
||||||
|
category: 'Tecnología',
|
||||||
|
brand: null,
|
||||||
|
images: []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
2,
|
2,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ interface StoreHomeProductCardViewModel {
|
|||||||
originalPrice: number;
|
originalPrice: number;
|
||||||
discount: null;
|
discount: null;
|
||||||
transferPrice: null;
|
transferPrice: null;
|
||||||
imageUrl: null;
|
imageUrl: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -42,7 +42,7 @@ export class StoreHomePageComponent implements OnInit, OnDestroy {
|
|||||||
originalPrice: this.parseProductPrice(product.precio),
|
originalPrice: this.parseProductPrice(product.precio),
|
||||||
discount: null,
|
discount: null,
|
||||||
transferPrice: null,
|
transferPrice: null,
|
||||||
imageUrl: null
|
imageUrl: product.images?.[0] ?? null
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user