feat: refactor services injection in search and store home components, add direct purchase event tests
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
|||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
DestroyRef,
|
DestroyRef,
|
||||||
|
Injector,
|
||||||
computed,
|
computed,
|
||||||
inject,
|
inject,
|
||||||
signal,
|
signal,
|
||||||
@@ -28,7 +29,6 @@ import {
|
|||||||
ProductListCartEvent,
|
ProductListCartEvent,
|
||||||
ProductListBuyEvent,
|
ProductListBuyEvent,
|
||||||
ProductListComponent,
|
ProductListComponent,
|
||||||
ProductListItem,
|
|
||||||
} from '../../../../shared/components/product-list/product-list.component';
|
} from '../../../../shared/components/product-list/product-list.component';
|
||||||
|
|
||||||
interface SearchRouteState {
|
interface SearchRouteState {
|
||||||
@@ -46,9 +46,8 @@ interface SearchRouteState {
|
|||||||
export class SearchPageComponent {
|
export class SearchPageComponent {
|
||||||
private readonly minSearchLength = 3;
|
private readonly minSearchLength = 3;
|
||||||
private readonly cartService = inject(CartService);
|
private readonly cartService = inject(CartService);
|
||||||
private readonly authService = inject(AuthService);
|
|
||||||
private readonly catalogService = inject(CatalogService);
|
private readonly catalogService = inject(CatalogService);
|
||||||
private readonly checkoutService = inject(CheckoutService);
|
private readonly injector = inject(Injector);
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
private readonly route = inject(ActivatedRoute);
|
private readonly route = inject(ActivatedRoute);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
@@ -147,7 +146,7 @@ export class SearchPageComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.authService.user()) {
|
if (!this.injector.get(AuthService).user()) {
|
||||||
await this.router.navigate(['/login'], {
|
await this.router.navigate(['/login'], {
|
||||||
queryParams: { returnUrl: `/producto/${event.product.id}` },
|
queryParams: { returnUrl: `/producto/${event.product.id}` },
|
||||||
});
|
});
|
||||||
@@ -162,7 +161,7 @@ export class SearchPageComponent {
|
|||||||
|
|
||||||
this.creatingDirectPurchase.set(true);
|
this.creatingDirectPurchase.set(true);
|
||||||
try {
|
try {
|
||||||
const purchase = await this.checkoutService.startCheckout(tenant.codigo, {
|
const purchase = await this.injector.get(CheckoutService).startCheckout(tenant.codigo, {
|
||||||
direct_item: {
|
direct_item: {
|
||||||
catalog_item_id: event.product.id,
|
catalog_item_id: event.product.id,
|
||||||
variant_id: event.variant ?? null,
|
variant_id: event.variant ?? null,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
|
Injector,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
computed,
|
computed,
|
||||||
@@ -22,7 +23,6 @@ import {
|
|||||||
ProductListComponent,
|
ProductListComponent,
|
||||||
ProductListCartEvent,
|
ProductListCartEvent,
|
||||||
ProductListBuyEvent,
|
ProductListBuyEvent,
|
||||||
ProductListItem,
|
|
||||||
} from '../../../../shared/components/product-list/product-list.component';
|
} from '../../../../shared/components/product-list/product-list.component';
|
||||||
import { HeroBannerComponent } from '../../../../shared/components/hero-banner/hero-banner.component';
|
import { HeroBannerComponent } from '../../../../shared/components/hero-banner/hero-banner.component';
|
||||||
import { MainCarouselComponent } from '../../../../shared/components/main-carousel/main-carousel.component';
|
import { MainCarouselComponent } from '../../../../shared/components/main-carousel/main-carousel.component';
|
||||||
@@ -46,9 +46,8 @@ import {
|
|||||||
})
|
})
|
||||||
export class StoreHomePageComponent implements OnInit, OnDestroy {
|
export class StoreHomePageComponent implements OnInit, OnDestroy {
|
||||||
private readonly cartService = inject(CartService);
|
private readonly cartService = inject(CartService);
|
||||||
private readonly authService = inject(AuthService);
|
|
||||||
private readonly catalogService = inject(CatalogService);
|
private readonly catalogService = inject(CatalogService);
|
||||||
private readonly checkoutService = inject(CheckoutService);
|
private readonly injector = inject(Injector);
|
||||||
private readonly route = inject(ActivatedRoute);
|
private readonly route = inject(ActivatedRoute);
|
||||||
private readonly router = inject(Router);
|
private readonly router = inject(Router);
|
||||||
private readonly tenantService = inject(TenantService);
|
private readonly tenantService = inject(TenantService);
|
||||||
@@ -70,7 +69,8 @@ export class StoreHomePageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const resolvedData = this.route.snapshot.data['catalogData'] as
|
const resolvedData = this.route.snapshot.data['catalogData'] as
|
||||||
StoreHomeCatalogResolvedData | undefined;
|
| StoreHomeCatalogResolvedData
|
||||||
|
| undefined;
|
||||||
|
|
||||||
if (resolvedData) {
|
if (resolvedData) {
|
||||||
this.applyResolvedData(resolvedData);
|
this.applyResolvedData(resolvedData);
|
||||||
@@ -134,7 +134,7 @@ export class StoreHomePageComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.authService.user()) {
|
if (!this.injector.get(AuthService).user()) {
|
||||||
await this.router.navigate(['/login'], {
|
await this.router.navigate(['/login'], {
|
||||||
queryParams: { returnUrl: `/producto/${event.product.id}` },
|
queryParams: { returnUrl: `/producto/${event.product.id}` },
|
||||||
});
|
});
|
||||||
@@ -149,7 +149,7 @@ export class StoreHomePageComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.creatingDirectPurchase.set(true);
|
this.creatingDirectPurchase.set(true);
|
||||||
try {
|
try {
|
||||||
const purchase = await this.checkoutService.startCheckout(tenant.codigo, {
|
const purchase = await this.injector.get(CheckoutService).startCheckout(tenant.codigo, {
|
||||||
direct_item: {
|
direct_item: {
|
||||||
catalog_item_id: event.product.id,
|
catalog_item_id: event.product.id,
|
||||||
variant_id: event.variant ?? null,
|
variant_id: event.variant ?? null,
|
||||||
|
|||||||
@@ -126,6 +126,40 @@ describe('ProductListComponent', () => {
|
|||||||
).toHaveLength(2);
|
).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('emits a direct-purchase event with the row quantity and selected variant', async () => {
|
||||||
|
const fixture = await render('row');
|
||||||
|
const buySpy = vi.fn();
|
||||||
|
fixture.componentInstance.buy.subscribe(buySpy);
|
||||||
|
const rowCard = fixture.nativeElement.querySelector('app-product-row-card') as HTMLElement;
|
||||||
|
|
||||||
|
(rowCard.querySelector('.btn-primary') as HTMLButtonElement).click();
|
||||||
|
|
||||||
|
expect(buySpy).toHaveBeenCalledWith({
|
||||||
|
product: items[0],
|
||||||
|
quantity: 1,
|
||||||
|
variant: null,
|
||||||
|
directPurchase: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('emits a direct-purchase event with the column quantity', async () => {
|
||||||
|
const fixture = await render('column_with_cart');
|
||||||
|
const buySpy = vi.fn();
|
||||||
|
fixture.componentInstance.buy.subscribe(buySpy);
|
||||||
|
const card = fixture.nativeElement.querySelector(
|
||||||
|
'app-product-vertical-with-cart-card',
|
||||||
|
) as HTMLElement;
|
||||||
|
|
||||||
|
(card.querySelector('.btn-primary') as HTMLButtonElement).click();
|
||||||
|
|
||||||
|
expect(buySpy).toHaveBeenCalledWith({
|
||||||
|
product: items[0],
|
||||||
|
quantity: 1,
|
||||||
|
variant: null,
|
||||||
|
directPurchase: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('renders pagination and emits the requested page', async () => {
|
it('renders pagination and emits the requested page', async () => {
|
||||||
const fixture = await render('row');
|
const fixture = await render('row');
|
||||||
const pageChangeSpy = vi.fn();
|
const pageChangeSpy = vi.fn();
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<div class="product-row-card border rounded bg-white shadow-sm d-flex justify-content-between p-3 gap-3">
|
<div
|
||||||
|
class="product-row-card border rounded bg-white shadow-sm d-flex justify-content-between p-3 gap-3"
|
||||||
|
>
|
||||||
<!-- Left Side: Title and Description -->
|
<!-- Left Side: Title and Description -->
|
||||||
<div class="product-row-card__info d-flex flex-column justify-content-center flex-grow-1">
|
<div class="product-row-card__info d-flex flex-column justify-content-center flex-grow-1">
|
||||||
<h3 class="product-row-card__title text-uppercase mb-1 m-0">
|
<h3 class="product-row-card__title text-uppercase mb-1 m-0">
|
||||||
@@ -19,9 +21,7 @@
|
|||||||
{{ formattedPrice() }}
|
{{ formattedPrice() }}
|
||||||
</span>
|
</span>
|
||||||
<div class="product-row-card__btn-wrapper">
|
<div class="product-row-card__btn-wrapper">
|
||||||
<app-button variant="primary" (click)="onBuy()">
|
<app-button variant="primary" (click)="onBuy()"> Comprar </app-button>
|
||||||
Comprar
|
|
||||||
</app-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -35,12 +35,10 @@
|
|||||||
</select>
|
</select>
|
||||||
}
|
}
|
||||||
|
|
||||||
<app-quantity-selector [(quantity)]="quantity" ></app-quantity-selector>
|
<app-quantity-selector [(quantity)]="quantity"></app-quantity-selector>
|
||||||
|
|
||||||
<div class="product-row-card__btn-wrapper">
|
<div class="product-row-card__btn-wrapper">
|
||||||
<app-button variant="secondary" (click)="onAddToCart()">
|
<app-button variant="secondary" (click)="onAddToCart()"> Agregar al carrito </app-button>
|
||||||
Agregar al carrito
|
|
||||||
</app-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
import { ChangeDetectionStrategy, Component, computed, effect, input, output, model } from '@angular/core';
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
computed,
|
||||||
|
effect,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
model,
|
||||||
|
} from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { ButtonComponent } from '../button/button.component';
|
import { ButtonComponent } from '../button/button.component';
|
||||||
import { QuantitySelectorComponent } from '../quantity-selector/quantity-selector.component';
|
import { QuantitySelectorComponent } from '../quantity-selector/quantity-selector.component';
|
||||||
@@ -53,7 +61,7 @@ export class ProductRowCardComponent {
|
|||||||
protected onAddToCart(): void {
|
protected onAddToCart(): void {
|
||||||
this.addToCart.emit({
|
this.addToCart.emit({
|
||||||
quantity: this.quantity(),
|
quantity: this.quantity(),
|
||||||
variant: this.selectedVariant()
|
variant: this.selectedVariant(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ describe('ProductVerticalWithCartCardComponent', () => {
|
|||||||
) as HTMLButtonElement;
|
) as HTMLButtonElement;
|
||||||
button.click();
|
button.click();
|
||||||
|
|
||||||
expect(buySpy).toHaveBeenCalledOnce();
|
expect(buySpy).toHaveBeenCalledWith({ quantity: 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('emits addToCart with the current quantity', async () => {
|
it('emits addToCart with the current quantity', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user