feat: implement cart component with mock data and styling for improved cart functionality

This commit is contained in:
2026-07-01 16:51:23 -03:00
parent ac9d1fdc85
commit af406c215a
9 changed files with 543 additions and 1 deletions

View File

@@ -0,0 +1,42 @@
<section class="cart" [style.background-color]="backgroundColor()">
<header class="cart__header">
<h2 class="cart__title">{{ title() }}</h2>
@if (showClose()) {
<button class="cart__close" type="button" aria-label="Cerrar carrito" (click)="closed.emit()">
<i class="fa-solid fa-xmark"></i>
</button>
}
</header>
<div class="cart__items">
@for (item of items(); track item.product + item.discountedPrice) {
<app-cart-item
[imageUrl]="item.imageUrl"
[product]="item.product"
[originalPrice]="item.originalPrice"
[discountedPrice]="item.discountedPrice"
[discountPercentage]="item.discountPercentage"
[attributes]="item.attributes"
[quantity]="item.quantity"
/>
}
</div>
<footer class="cart__summary">
<div class="cart__summary-row">
<span class="cart__summary-label">Subtotal:</span>
<span class="cart__summary-value">{{ formattedSubtotal() }}</span>
</div>
<div class="cart__summary-row">
<span class="cart__summary-label">Descuento:</span>
<span class="cart__summary-value">{{ formattedDiscount() }}</span>
</div>
<div class="cart__summary-row cart__summary-row--total">
<span class="cart__summary-label">TOTAL:</span>
<span class="cart__summary-value">{{ formattedTotal() }}</span>
</div>
</footer>
</section>

View File

@@ -0,0 +1,104 @@
:host {
display: block;
width: 100%;
max-width: 370px;
}
.cart {
display: grid;
gap: 0.75rem;
width: 100%;
color: #666666;
border-radius: 0;
overflow: hidden;
&__header,
&__summary {
background-color: inherit;
}
&__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 8px 0 24px;
}
&__title {
margin: 0;
color: #a0a0a0;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.04em;
}
&__close {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border: 0;
background: transparent;
color: #a0a0a0;
font-size: 14px;
}
&__items {
display: grid;
gap: 8px;
max-height: 254px;
padding: 0 0 0 24px;
overflow-y: auto;
scrollbar-color: #d5d5d5 transparent;
scrollbar-width: thin;
}
&__items::-webkit-scrollbar {
width: 6px;
}
&__items::-webkit-scrollbar-thumb {
border-radius: 999px;
background-color: #d5d5d5;
}
&__summary {
display: grid;
gap: 0.35rem;
padding: 8px 22px 14px 24px;
}
&__summary-row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 1rem;
}
&__summary-label,
&__summary-value {
color: #a0a0a0;
font-size: 13px;
}
&__summary-label {
font-weight: 325;
}
&__summary-value {
font-weight: 700;
}
&__summary-row--total {
margin-top: 0.2rem;
}
&__summary-row--total .cart__summary-label,
&__summary-row--total .cart__summary-value {
color: #666666;
font-size: 15px;
font-weight: 700;
}
}

View File

@@ -0,0 +1,43 @@
import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
import { CartItemAttribute, CartItemComponent } from '../cart-item/cart-item.component';
export interface CartItemMock {
imageUrl: string | null;
product: string;
originalPrice: number | null;
discountedPrice: number;
discountPercentage: number | null;
attributes: CartItemAttribute[];
quantity: number;
}
@Component({
selector: 'app-cart',
standalone: true,
imports: [CartItemComponent],
templateUrl: './cart.component.html',
styleUrl: './cart.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CartComponent {
readonly title = input<string>('CARRITO');
readonly showClose = input<boolean>(false);
readonly items = input<CartItemMock[]>([]);
readonly subtotal = input<number>(0);
readonly discount = input<number>(0);
readonly total = input<number>(0);
readonly backgroundColor = input<string>('#ffffff');
readonly closed = output<void>();
protected readonly formattedSubtotal = computed(() => this.formatCurrency(this.subtotal()));
protected readonly formattedDiscount = computed(() => this.formatCurrency(this.discount()));
protected readonly formattedTotal = computed(() => this.formatCurrency(this.total()));
private formatCurrency(value: number): string {
const rounded = Math.round(value);
const parts = rounded.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.');
return `$ ${parts.join(',')}`;
}
}