From 394a1dde0d72e147797f47366530fbbe481b96c2 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Thu, 2 Jul 2026 08:47:52 -0300 Subject: [PATCH] feat: implement quantity selector component for improved cart functionality --- .../product-detail-page.component.html | 29 +++--------- .../product-detail-page.component.scss | 38 --------------- .../product-detail-page.component.spec.ts | 4 +- .../product-detail-page.component.ts | 10 +++- .../quantity-selector.component.html | 23 +++++++++ .../quantity-selector.component.scss | 47 +++++++++++++++++++ .../quantity-selector.component.ts | 35 ++++++++++++++ 7 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 src/app/shared/components/quantity-selector/quantity-selector.component.html create mode 100644 src/app/shared/components/quantity-selector/quantity-selector.component.scss create mode 100644 src/app/shared/components/quantity-selector/quantity-selector.component.ts diff --git a/src/app/features/store/pages/product-detail-page/product-detail-page.component.html b/src/app/features/store/pages/product-detail-page/product-detail-page.component.html index 892f588..f934867 100644 --- a/src/app/features/store/pages/product-detail-page/product-detail-page.component.html +++ b/src/app/features/store/pages/product-detail-page/product-detail-page.component.html @@ -53,28 +53,13 @@
-
- - - {{ quantity() }} - - -
+
{ decreaseButton.click(); fixture.detectChanges(); - expect(element.querySelector('.product-detail__quantity-value')?.textContent?.trim()).toBe('1'); + expect(element.querySelector('.quantity-selector__value')?.textContent?.trim()).toBe('1'); increaseButton.click(); increaseButton.click(); fixture.detectChanges(); - expect(element.querySelector('.product-detail__quantity-value')?.textContent?.trim()).toBe('3'); + expect(element.querySelector('.quantity-selector__value')?.textContent?.trim()).toBe('3'); }); it('toggles the full description state when overflow is available', async () => { diff --git a/src/app/features/store/pages/product-detail-page/product-detail-page.component.ts b/src/app/features/store/pages/product-detail-page/product-detail-page.component.ts index b7d0878..43c22eb 100644 --- a/src/app/features/store/pages/product-detail-page/product-detail-page.component.ts +++ b/src/app/features/store/pages/product-detail-page/product-detail-page.component.ts @@ -29,11 +29,19 @@ import { import { ProductCarouselComponent } from '../../components/product-carousel/product-carousel.component'; import { ButtonComponent } from '../../../../shared/components/button/button.component'; import { ProductAttributeSelectorComponent } from '../../components/product-attribute-selector/product-attribute-selector.component'; +import { QuantitySelectorComponent } from '../../../../shared/components/quantity-selector/quantity-selector.component'; @Component({ selector: 'app-product-detail-page', standalone: true, - imports: [CommonModule, RouterModule, ProductCarouselComponent, ButtonComponent, ProductAttributeSelectorComponent], + imports: [ + CommonModule, + RouterModule, + ProductCarouselComponent, + ButtonComponent, + ProductAttributeSelectorComponent, + QuantitySelectorComponent + ], templateUrl: './product-detail-page.component.html', styleUrl: './product-detail-page.component.scss', changeDetection: ChangeDetectionStrategy.OnPush diff --git a/src/app/shared/components/quantity-selector/quantity-selector.component.html b/src/app/shared/components/quantity-selector/quantity-selector.component.html new file mode 100644 index 0000000..c991d01 --- /dev/null +++ b/src/app/shared/components/quantity-selector/quantity-selector.component.html @@ -0,0 +1,23 @@ +
+ + + {{ quantity() }} + + +
diff --git a/src/app/shared/components/quantity-selector/quantity-selector.component.scss b/src/app/shared/components/quantity-selector/quantity-selector.component.scss new file mode 100644 index 0000000..580c737 --- /dev/null +++ b/src/app/shared/components/quantity-selector/quantity-selector.component.scss @@ -0,0 +1,47 @@ +:host { + display: inline-block; +} + +.quantity-selector { + display: inline-flex; + align-items: center; + border: 1px solid #d8d8d8; + border-radius: 6px; + overflow: hidden; + min-height: 44px; + background: #f6f6f6; + + &__button { + width: 25px; + height: 44px; + padding: 0; + font-size: 20px; + font-weight: 700; + line-height: 1; + color: #6f6f6f; + background: #f6f6f6; + border: 0; + transition: background-color 0.2s ease, color 0.2s ease; + cursor: pointer; + + &:not(:disabled):hover { + background-color: #e9e9e9; + color: #333333; + } + + &:disabled { + opacity: 0.4; + cursor: not-allowed; + } + } + + &__value { + min-width: 35px; + text-align: center; + font-size: 16px; + font-weight: 700; + line-height: 1; + color: #6f6f6f; + user-select: none; + } +} diff --git a/src/app/shared/components/quantity-selector/quantity-selector.component.ts b/src/app/shared/components/quantity-selector/quantity-selector.component.ts new file mode 100644 index 0000000..6ae9aee --- /dev/null +++ b/src/app/shared/components/quantity-selector/quantity-selector.component.ts @@ -0,0 +1,35 @@ +import { ChangeDetectionStrategy, Component, input, output } from '@angular/core'; + +@Component({ + selector: 'app-quantity-selector', + standalone: true, + imports: [], + templateUrl: './quantity-selector.component.html', + styleUrl: './quantity-selector.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class QuantitySelectorComponent { + readonly quantity = input(1); + readonly min = input(1); + readonly max = input(100); + + readonly increase = output(); + readonly decrease = output(); + readonly quantityChange = output(); + + protected onDecrease(): void { + if (this.quantity() > this.min()) { + const newValue = this.quantity() - 1; + this.decrease.emit(); + this.quantityChange.emit(newValue); + } + } + + protected onIncrease(): void { + if (this.quantity() < this.max()) { + const newValue = this.quantity() + 1; + this.increase.emit(); + this.quantityChange.emit(newValue); + } + } +}