feat: enhance cart functionality with quantity update and removal features, integrating toast notifications for user feedback
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
</header>
|
||||
|
||||
<div class="d-grid gap-2 flex-grow-1 overflow-y-auto cart-items-container">
|
||||
@for (item of items(); track item.product + item.discountedPrice) {
|
||||
@for (item of items(); track item.product + item.discountedPrice + resetKey(); let idx = $index) {
|
||||
<app-cart-item
|
||||
[imageUrl]="item.imageUrl"
|
||||
[product]="item.product"
|
||||
@@ -19,6 +19,8 @@
|
||||
[discountPercentage]="item.discountPercentage"
|
||||
[attributes]="item.attributes"
|
||||
[quantity]="item.quantity"
|
||||
(quantityChange)="onItemQuantityChange(idx, $event)"
|
||||
(remove)="onItemRemove(idx)"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, computed, inject, input, output, signal } from '@angular/core';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Subject, EMPTY } from 'rxjs';
|
||||
import { catchError, debounceTime, groupBy, mergeMap, switchMap, tap } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { CartItemAttribute, CartItemComponent } from '../cart-item/cart-item.component';
|
||||
import { CartService } from '../../../core/services/cart/cart.service';
|
||||
import { ToastService } from '../../../core/services/toast.service';
|
||||
|
||||
export interface CartItemMock {
|
||||
imageUrl: string | null;
|
||||
@@ -20,6 +26,10 @@ export interface CartItemMock {
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CartComponent {
|
||||
private readonly cartService = inject(CartService);
|
||||
private readonly toastService = inject(ToastService);
|
||||
private readonly quantityUpdates$ = new Subject<{ productVariantId: number; quantity: number }>();
|
||||
|
||||
readonly title = input<string>('CARRITO');
|
||||
readonly showClose = input<boolean>(false);
|
||||
readonly items = input<CartItemMock[]>([]);
|
||||
@@ -30,6 +40,60 @@ export class CartComponent {
|
||||
|
||||
readonly closed = output<void>();
|
||||
|
||||
protected readonly resetKey = signal(0);
|
||||
|
||||
constructor() {
|
||||
this.quantityUpdates$.pipe(
|
||||
groupBy(update => update.productVariantId),
|
||||
mergeMap(group$ => group$.pipe(
|
||||
debounceTime(1000),
|
||||
switchMap(update => this.cartService.updateItemQuantity(update.productVariantId, update.quantity).pipe(
|
||||
tap({
|
||||
next: (res) => {
|
||||
const msg = res.message || 'Cantidad de producto actualizada.';
|
||||
this.toastService.success(msg);
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
console.error('Error updating cart quantity', err);
|
||||
const msg = err.error?.message || 'Error al actualizar la cantidad del producto.';
|
||||
this.toastService.danger(msg);
|
||||
this.resetKey.update(k => k + 1);
|
||||
}
|
||||
}),
|
||||
catchError(() => EMPTY)
|
||||
))
|
||||
)),
|
||||
takeUntilDestroyed()
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
protected onItemQuantityChange(index: number, newQuantity: number): void {
|
||||
const item = this.cartService.cart()?.items[index];
|
||||
if (item) {
|
||||
this.quantityUpdates$.next({
|
||||
productVariantId: item.product_variant_id,
|
||||
quantity: newQuantity
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected onItemRemove(index: number): void {
|
||||
const item = this.cartService.cart()?.items[index];
|
||||
if (item) {
|
||||
this.cartService.removeItem(item.product_variant_id).subscribe({
|
||||
next: (res) => {
|
||||
const msg = res.message || 'Producto eliminado del carrito.';
|
||||
this.toastService.success(msg);
|
||||
},
|
||||
error: (err: HttpErrorResponse) => {
|
||||
console.error('Error removing item from cart', err);
|
||||
const msg = err.error?.message || 'Error al eliminar el producto del carrito.';
|
||||
this.toastService.danger(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly formattedSubtotal = computed(() => this.formatCurrency(this.subtotal()));
|
||||
protected readonly formattedDiscount = computed(() => this.formatCurrency(this.discount()));
|
||||
protected readonly formattedTotal = computed(() => this.formatCurrency(this.total()));
|
||||
@@ -41,3 +105,4 @@ export class CartComponent {
|
||||
return `$ ${parts.join(',')}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user