feat(cart): notify catalog availability changes

This commit is contained in:
2026-08-21 14:19:28 -03:00
parent 02ff829c06
commit 70060f65ec
3 changed files with 47 additions and 0 deletions

View File

@@ -7,11 +7,13 @@ import { CartService } from './cart.service';
import { TenantService } from '../tenant.service';
import { Cart } from './cart.interface';
import { LOADING_MODE } from '../global-loading/loading-mode';
import { CatalogAvailabilityService } from '../catalog/catalog-availability.service';
describe('CartService', () => {
let service: CartService;
let httpMock: HttpTestingController;
let tenantServiceMock: any;
let catalogAvailabilityService: CatalogAvailabilityService;
const mockCart: Cart = {
id: 123,
@@ -53,6 +55,7 @@ describe('CartService', () => {
});
service = TestBed.inject(CartService);
catalogAvailabilityService = TestBed.inject(CatalogAvailabilityService);
httpMock = TestBed.inject(HttpTestingController);
});
@@ -101,6 +104,9 @@ describe('CartService', () => {
});
it('should add item and update signal', () => {
const availabilityChanged = vi.fn();
catalogAvailabilityService.availabilityChanged$.subscribe(availabilityChanged);
service.addItem(5, 10, 2).subscribe((res) => {
expect(res.data).toEqual(mockCart);
expect(service.cart()).toEqual(mockCart);
@@ -115,9 +121,13 @@ describe('CartService', () => {
});
expect(req.request.withCredentials).toBe(true);
req.flush({ data: mockCart });
expect(availabilityChanged).toHaveBeenCalledOnce();
});
it('should update item quantity and update signal', () => {
const availabilityChanged = vi.fn();
catalogAvailabilityService.availabilityChanged$.subscribe(availabilityChanged);
const updatedCart = { ...mockCart, subtotal: '30.00' };
updatedCart.items[0].cantidad = 3;
@@ -131,9 +141,13 @@ describe('CartService', () => {
expect(req.request.body).toEqual({ cantidad: 3 });
expect(req.request.withCredentials).toBe(true);
req.flush({ data: updatedCart });
expect(availabilityChanged).toHaveBeenCalledOnce();
});
it('should remove item and update signal', () => {
const availabilityChanged = vi.fn();
catalogAvailabilityService.availabilityChanged$.subscribe(availabilityChanged);
const emptyCart: Cart = {
id: 123,
tenant_codigo: 'acme',
@@ -151,5 +165,18 @@ describe('CartService', () => {
expect(req.request.method).toBe('DELETE');
expect(req.request.withCredentials).toBe(true);
req.flush({ data: emptyCart });
expect(availabilityChanged).toHaveBeenCalledOnce();
});
it('does not notify an availability change when a cart mutation fails', () => {
const availabilityChanged = vi.fn();
catalogAvailabilityService.availabilityChanged$.subscribe(availabilityChanged);
service.removeItem(10).subscribe({ error: vi.fn() });
const req = httpMock.expectOne('http://api.test/tenants/acme/cart/items/10');
req.flush({ message: 'Error' }, { status: 500, statusText: 'Server Error' });
expect(availabilityChanged).not.toHaveBeenCalled();
});
});

View File

@@ -3,6 +3,7 @@ import { catchError, map, Observable, tap } from 'rxjs';
import { ApiResponse } from '../api-response.interface';
import { BaseApiService } from '../base-api.service';
import { CatalogAvailabilityService } from '../catalog/catalog-availability.service';
import { TenantService } from '../tenant.service';
import { Cart } from './cart.interface';
@@ -10,6 +11,7 @@ import { Cart } from './cart.interface';
providedIn: 'root',
})
export class CartService extends BaseApiService {
private readonly catalogAvailabilityService = inject(CatalogAvailabilityService);
private readonly tenantService = inject(TenantService);
private readonly cartState = signal<Cart | null>(null);
@@ -60,6 +62,7 @@ export class CartService extends BaseApiService {
.pipe(
tap((response) => {
this.cartState.set(response.data);
this.catalogAvailabilityService.notifyAvailabilityChanged();
this.isUpdatingState.set(false);
}),
catchError((error) => {
@@ -93,6 +96,7 @@ export class CartService extends BaseApiService {
.pipe(
tap((response) => {
this.cartState.set(response.data);
this.catalogAvailabilityService.notifyAvailabilityChanged();
this.isUpdatingState.set(false);
}),
catchError((error) => {
@@ -111,6 +115,7 @@ export class CartService extends BaseApiService {
.pipe(
tap((response) => {
this.cartState.set(response.data);
this.catalogAvailabilityService.notifyAvailabilityChanged();
this.isUpdatingState.set(false);
}),
catchError((error) => {

View File

@@ -0,0 +1,15 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class CatalogAvailabilityService {
private readonly availabilityChangedSubject = new Subject<void>();
readonly availabilityChanged$: Observable<void> = this.availabilityChangedSubject.asObservable();
notifyAvailabilityChanged(): void {
this.availabilityChangedSubject.next();
}
}