feat: enhance product attributes and event date handling for improved user experience and data management

This commit is contained in:
2026-08-07 14:16:02 -03:00
parent 8d88e1bb13
commit 1977df6765
18 changed files with 368 additions and 187 deletions

View File

@@ -109,6 +109,8 @@ export class ProductListComponent {
return (item.variants ?? []).map((variant) => ({
value: variant.id,
label: Object.values(variant.values).join(' / ') || `Variante ${variant.id}`,
descripcion: variant.descripcion,
precio: variant.precio,
}));
}

View File

@@ -6,9 +6,9 @@
<h3 class="product-row-card__title text-uppercase mb-1 m-0">
{{ title() }}
</h3>
@if (description()) {
@if (effectiveDescription()) {
<p class="product-row-card__description m-0 mt-1">
{{ description() }}
{{ effectiveDescription() }}
</p>
}
</div>

View File

@@ -14,6 +14,8 @@ import { QuantitySelectorComponent } from '../quantity-selector/quantity-selecto
export interface Variant {
label: string;
value: any;
descripcion?: string | null;
precio?: string | number;
}
@Component({
@@ -53,11 +55,20 @@ export class ProductRowCardComponent {
});
}
// Formatted string for price: "$ 10.000"
readonly formattedPrice = computed(() => {
return this.formatCurrency(this.price());
protected readonly selectedVariantData = computed(() =>
this.variants().find((variant) => Object.is(variant.value, this.selectedVariant())),
);
protected readonly effectiveDescription = computed(
() => this.selectedVariantData()?.descripcion ?? this.description(),
);
protected readonly effectivePrice = computed(() => {
const variantPrice = Number(this.selectedVariantData()?.precio);
return Number.isFinite(variantPrice) ? variantPrice : this.price();
});
readonly formattedPrice = computed(() => this.formatCurrency(this.effectivePrice()));
protected onAddToCart(): void {
this.addToCart.emit({
quantity: this.quantity(),

View File

@@ -2,8 +2,8 @@
<div class="product-vertical-with-cart-card__content">
<h3 class="product-vertical-with-cart-card__title">{{ title() }}</h3>
@if (description()) {
<p class="product-vertical-with-cart-card__description">{{ description() }}</p>
@if (effectiveDescription()) {
<p class="product-vertical-with-cart-card__description">{{ effectiveDescription() }}</p>
}
</div>

View File

@@ -177,4 +177,45 @@ describe('ProductVerticalWithCartCardComponent', () => {
expect(buySpy).toHaveBeenCalledWith({ quantity: 1, variant: 31 });
});
it('prioritizes the selected variant description and price', async () => {
const fixture = await createComponent('Descripción general');
fixture.componentRef.setInput('variants', [
{
id: 40,
descripcion: 'Almuerzo en comedor',
precio: '10000.00',
values: { servicio: 'Comedor' },
},
{
id: 41,
descripcion: 'Almuerzo en vianda',
precio: '8000.00',
values: { servicio: 'Vianda' },
},
]);
fixture.detectChanges();
const element = fixture.nativeElement as HTMLElement;
expect(
element.querySelector('.product-vertical-with-cart-card__description')?.textContent,
).toContain('Almuerzo en comedor');
expect(
element.querySelector('.product-vertical-with-cart-card__price')?.textContent?.trim(),
).toBe('$ 10.000');
const select = element.querySelector(
'.product-vertical-with-cart-card__variant-select',
) as HTMLSelectElement;
select.value = select.options[1].value;
select.dispatchEvent(new Event('change'));
fixture.detectChanges();
expect(
element.querySelector('.product-vertical-with-cart-card__description')?.textContent,
).toContain('Almuerzo en vianda');
expect(
element.querySelector('.product-vertical-with-cart-card__price')?.textContent?.trim(),
).toBe('$ 8.000');
});
});

View File

@@ -16,6 +16,8 @@ import { QuantitySelectorComponent } from '../quantity-selector/quantity-selecto
export interface VerticalCartVariant {
id: number;
descripcion?: string | null;
precio?: string | number;
values: Record<string, string>;
}
@@ -46,7 +48,18 @@ export class ProductVerticalWithCartCardComponent {
protected readonly selectedValues = signal<Record<string, string>>({});
protected readonly formattedPrice = computed(() => this.formatCurrency(this.price()));
protected readonly selectedVariantData = computed(() =>
this.variants().find((variant) => variant.id === this.selectedVariant()),
);
protected readonly effectiveDescription = computed(
() => this.selectedVariantData()?.descripcion ?? this.description(),
);
protected readonly effectivePrice = computed(() => {
const variantPrice = Number(this.selectedVariantData()?.precio);
return Number.isFinite(variantPrice) ? variantPrice : this.price();
});
protected readonly formattedPrice = computed(() => this.formatCurrency(this.effectivePrice()));
protected readonly variantSelectors = computed<VariantSelector[]>(() => {
const variants = this.variants();
const keys = Array.from(new Set(variants.flatMap((variant) => Object.keys(variant.values))));