feat: integrate quantity selector component into cart and product detail pages for enhanced functionality
This commit is contained in:
@@ -54,11 +54,8 @@
|
|||||||
<section class="product-detail__section">
|
<section class="product-detail__section">
|
||||||
<div class="product-detail__purchase">
|
<div class="product-detail__purchase">
|
||||||
<app-quantity-selector
|
<app-quantity-selector
|
||||||
[quantity]="quantity()"
|
[(quantity)]="quantity"
|
||||||
[max]="selectedVariant()?.stock ?? 1"
|
[max]="selectedVariant()?.stock ?? 1"
|
||||||
(increase)="increaseQuantity()"
|
|
||||||
(decrease)="decreaseQuantity()"
|
|
||||||
(quantityChange)="quantity.set($event)"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="product-detail__actions">
|
<div class="product-detail__actions">
|
||||||
|
|||||||
@@ -215,14 +215,7 @@ export class ProductDetailPageComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected increaseQuantity(): void {
|
|
||||||
const currentStock = this.selectedVariant()?.stock ?? 1;
|
|
||||||
this.quantity.update((current) => current < currentStock ? current + 1 : current);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected decreaseQuantity(): void {
|
|
||||||
this.quantity.update((current) => Math.max(1, current - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected addToCart(): void {
|
protected addToCart(): void {
|
||||||
const variant = this.selectedVariant();
|
const variant = this.selectedVariant();
|
||||||
|
|||||||
@@ -33,11 +33,15 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex justify-content-end align-items-center mt-auto cart-item-actions" aria-hidden="true">
|
<div class="d-flex justify-content-end align-items-center mt-auto cart-item-actions">
|
||||||
<button class="border d-inline-flex align-items-center justify-content-center bg-white rounded-0 cart-item-qty-btn" type="button">-</button>
|
<app-quantity-selector
|
||||||
<span class="border d-inline-flex align-items-center justify-content-center bg-white rounded-0 cart-item-qty-value" >{{ quantity() }}</span>
|
size="small"
|
||||||
<button class="border d-inline-flex align-items-center justify-content-center bg-white rounded-0 cart-item-qty-btn" type="button">+</button>
|
[quantity]="quantity()"
|
||||||
<button class="border-0 bg-transparent d-inline-flex align-items-center justify-content-center cart-item-remove-btn" type="button">
|
(quantityChange)="onQuantityChange($event)"
|
||||||
|
(increase)="onIncrease()"
|
||||||
|
(decrease)="onDecrease()"
|
||||||
|
/>
|
||||||
|
<button class="border-0 bg-transparent d-inline-flex align-items-center justify-content-center cart-item-remove-btn" type="button" (click)="onRemove()">
|
||||||
<i class="fa-solid fa-trash"></i>
|
<i class="fa-solid fa-trash"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,19 +92,8 @@
|
|||||||
gap: 0.125rem;
|
gap: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-item-qty-btn,
|
|
||||||
.cart-item-qty-value {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
border-color: #cfcfcf !important;
|
|
||||||
color: #666666;
|
|
||||||
font-size: 10px;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item-qty-btn {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item-remove-btn {
|
.cart-item-remove-btn {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
|
||||||
|
import { QuantitySelectorComponent } from '../quantity-selector/quantity-selector.component';
|
||||||
|
|
||||||
export interface CartItemAttribute {
|
export interface CartItemAttribute {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -8,6 +9,7 @@ export interface CartItemAttribute {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cart-item',
|
selector: 'app-cart-item',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
imports: [QuantitySelectorComponent],
|
||||||
templateUrl: './cart-item.component.html',
|
templateUrl: './cart-item.component.html',
|
||||||
styleUrl: './cart-item.component.scss',
|
styleUrl: './cart-item.component.scss',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
@@ -21,6 +23,27 @@ export class CartItemComponent {
|
|||||||
readonly attributes = input<CartItemAttribute[]>([]);
|
readonly attributes = input<CartItemAttribute[]>([]);
|
||||||
readonly quantity = input<number>(1);
|
readonly quantity = input<number>(1);
|
||||||
|
|
||||||
|
readonly quantityChange = output<number>();
|
||||||
|
readonly remove = output<void>();
|
||||||
|
readonly increase = output<void>();
|
||||||
|
readonly decrease = output<void>();
|
||||||
|
|
||||||
|
protected onQuantityChange(newQuantity: number): void {
|
||||||
|
this.quantityChange.emit(newQuantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onRemove(): void {
|
||||||
|
this.remove.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onIncrease(): void {
|
||||||
|
this.increase.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDecrease(): void {
|
||||||
|
this.decrease.emit();
|
||||||
|
}
|
||||||
|
|
||||||
protected readonly formattedOriginalPrice = computed(() => {
|
protected readonly formattedOriginalPrice = computed(() => {
|
||||||
const price = this.originalPrice();
|
const price = this.originalPrice();
|
||||||
return price === null ? null : this.formatCurrency(price);
|
return price === null ? null : this.formatCurrency(price);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="quantity-selector" aria-label="Selector de cantidad">
|
<div class="quantity-selector" [class.quantity-selector--small]="size() === 'small'" aria-label="Selector de cantidad">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="quantity-selector__button"
|
class="quantity-selector__button"
|
||||||
|
|||||||
@@ -44,4 +44,29 @@
|
|||||||
color: #6f6f6f;
|
color: #6f6f6f;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--small {
|
||||||
|
min-height: 18px;
|
||||||
|
border-radius: 0px;
|
||||||
|
border: 1px solid #cfcfcf;
|
||||||
|
background: #ffffff;
|
||||||
|
|
||||||
|
.quantity-selector__button {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
font-size: 10px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #666666;
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quantity-selector__value {
|
||||||
|
min-width: 18px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, input, model, output } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-quantity-selector',
|
selector: 'app-quantity-selector',
|
||||||
@@ -9,27 +9,25 @@ import { ChangeDetectionStrategy, Component, input, output } from '@angular/core
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class QuantitySelectorComponent {
|
export class QuantitySelectorComponent {
|
||||||
readonly quantity = input<number>(1);
|
readonly quantity = model<number>(1);
|
||||||
readonly min = input<number>(1);
|
readonly min = input<number>(1);
|
||||||
readonly max = input<number>(100);
|
readonly max = input<number>(100);
|
||||||
|
readonly size = input<'small' | 'medium'>('medium');
|
||||||
|
|
||||||
readonly increase = output<void>();
|
readonly increase = output<void>();
|
||||||
readonly decrease = output<void>();
|
readonly decrease = output<void>();
|
||||||
readonly quantityChange = output<number>();
|
|
||||||
|
|
||||||
protected onDecrease(): void {
|
protected onDecrease(): void {
|
||||||
if (this.quantity() > this.min()) {
|
if (this.quantity() > this.min()) {
|
||||||
const newValue = this.quantity() - 1;
|
this.quantity.set(this.quantity() - 1);
|
||||||
this.decrease.emit();
|
this.decrease.emit();
|
||||||
this.quantityChange.emit(newValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onIncrease(): void {
|
protected onIncrease(): void {
|
||||||
if (this.quantity() < this.max()) {
|
if (this.quantity() < this.max()) {
|
||||||
const newValue = this.quantity() + 1;
|
this.quantity.set(this.quantity() + 1);
|
||||||
this.increase.emit();
|
this.increase.emit();
|
||||||
this.quantityChange.emit(newValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user