diff --git a/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.ts b/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.ts
index c1db031..013d736 100644
--- a/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.ts
+++ b/src/app/features/componentes-test/pages/reutilizables-test-page/reutilizables-test-page.component.ts
@@ -6,6 +6,7 @@ import { PaginatorComponent } from '../../../../shared/components/paginator/pagi
import { ProductCardComponent } from '../../../../shared/components/product-card/product-card.component';
import { StoreSectionComponent } from '../../../../shared/components/store-section/store-section.component';
import { IconButtonComponent } from '../../../../shared/components/icon-button/icon-button.component';
+import { CartIconComponent } from '../../../../shared/components/cart-icon/cart-icon.component';
import { TenantService } from '../../../../core/services/tenant.service';
import { ToastService } from '../../../../core/services/toast.service';
@@ -18,7 +19,8 @@ import { ToastService } from '../../../../core/services/toast.service';
PaginatorComponent,
ProductCardComponent,
StoreSectionComponent,
- IconButtonComponent
+ IconButtonComponent,
+ CartIconComponent
],
templateUrl: './reutilizables-test-page.component.html',
styleUrl: './reutilizables-test-page.component.scss'
diff --git a/src/app/shared/components/cart-icon/cart-icon.component.html b/src/app/shared/components/cart-icon/cart-icon.component.html
new file mode 100644
index 0000000..7cf6e49
--- /dev/null
+++ b/src/app/shared/components/cart-icon/cart-icon.component.html
@@ -0,0 +1,13 @@
+
diff --git a/src/app/shared/components/cart-icon/cart-icon.component.scss b/src/app/shared/components/cart-icon/cart-icon.component.scss
new file mode 100644
index 0000000..49426b6
--- /dev/null
+++ b/src/app/shared/components/cart-icon/cart-icon.component.scss
@@ -0,0 +1,79 @@
+:host {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+.cart-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
+ border: none;
+ padding: 4px;
+ margin: 0;
+ color: #666666;
+ cursor: pointer;
+ outline: none;
+ transition: color 0.15s ease-in-out, transform 0.1s ease-in-out;
+ border-radius: 4px;
+
+ // Active state subtle scale down
+ &:active:not(:disabled) {
+ transform: scale(0.92);
+ }
+
+ // Focus ring for accessibility
+ &:focus-visible {
+ outline: 2px solid var(--tenant-primary);
+ outline-offset: 2px;
+ }
+
+ // Disabled state
+ &:disabled {
+ color: #A0A0A0;
+ cursor: not-allowed;
+ pointer-events: none;
+ }
+}
+
+// Hover/Active/Focus colors (non-disabled)
+.cart-icon:hover:not(:disabled),
+.cart-icon:focus-visible:not(:disabled),
+.cart-icon.hover-preview:not(:disabled),
+:host(.hover-preview) .cart-icon:not(:disabled) {
+ color: var(--tenant-primary);
+}
+
+.cart-icon__container {
+ position: relative;
+ display: inline-flex;
+}
+
+.cart-icon__glyph {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 23px;
+ height: 23px;
+ font-size: 23px;
+ line-height: 1;
+}
+
+.cart-icon__badge {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ min-width: 18px;
+ height: 18px;
+ border-radius: 9px;
+ background-color: var(--tenant-primary);
+ color: #ffffff;
+ font-size: 10px;
+ font-weight: 700;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 4px;
+ line-height: 1;
+ box-sizing: border-box;
+}
diff --git a/src/app/shared/components/cart-icon/cart-icon.component.spec.ts b/src/app/shared/components/cart-icon/cart-icon.component.spec.ts
new file mode 100644
index 0000000..eaca57a
--- /dev/null
+++ b/src/app/shared/components/cart-icon/cart-icon.component.spec.ts
@@ -0,0 +1,60 @@
+import { TestBed } from '@angular/core/testing';
+import { beforeEach, describe, expect, it } from 'vitest';
+
+import { CartIconComponent } from './cart-icon.component';
+
+describe('CartIconComponent', () => {
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [CartIconComponent]
+ }).compileComponents();
+ });
+
+ function setup(quantity?: number | null, disabled = false) {
+ const fixture = TestBed.createComponent(CartIconComponent);
+ if (quantity !== undefined) {
+ fixture.componentRef.setInput('quantity', quantity);
+ }
+ fixture.componentRef.setInput('disabled', disabled);
+ fixture.detectChanges();
+
+ return {
+ fixture,
+ element: fixture.nativeElement as HTMLElement
+ };
+ }
+
+ it('renders the cart shopping icon', () => {
+ const { element } = setup();
+ expect(element.querySelector('.fa-cart-shopping')).not.toBeNull();
+ });
+
+ it('does not render the badge when quantity is undefined', () => {
+ const { element } = setup();
+ expect(element.querySelector('[data-testid="cart-badge"]')).toBeNull();
+ });
+
+ it('does not render the badge when quantity is 0', () => {
+ const { element } = setup(0);
+ expect(element.querySelector('[data-testid="cart-badge"]')).toBeNull();
+ });
+
+ it('renders the badge with correct quantity when positive', () => {
+ const { element } = setup(3);
+ const badge = element.querySelector('[data-testid="cart-badge"]');
+ expect(badge).not.toBeNull();
+ expect(badge?.textContent?.trim()).toBe('3');
+ });
+
+ it('disables the button when disabled is true', () => {
+ const { element } = setup(undefined, true);
+ const button = element.querySelector('button');
+ expect(button?.disabled).toBe(true);
+ });
+
+ it('enables the button when disabled is false', () => {
+ const { element } = setup(undefined, false);
+ const button = element.querySelector('button');
+ expect(button?.disabled).toBe(false);
+ });
+});
diff --git a/src/app/shared/components/cart-icon/cart-icon.component.ts b/src/app/shared/components/cart-icon/cart-icon.component.ts
new file mode 100644
index 0000000..25d59fc
--- /dev/null
+++ b/src/app/shared/components/cart-icon/cart-icon.component.ts
@@ -0,0 +1,19 @@
+import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
+
+@Component({
+ selector: 'app-cart-icon',
+ imports: [],
+ templateUrl: './cart-icon.component.html',
+ styleUrl: './cart-icon.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class CartIconComponent {
+ readonly quantity = input
(undefined);
+ readonly disabled = input(false);
+ readonly ariaLabel = input('Carrito de compras');
+
+ protected readonly hasQuantity = computed(() => {
+ const q = this.quantity();
+ return q !== null && q !== undefined && q > 0;
+ });
+}