Compare commits
4 Commits
52f7b98162
...
f6ff91ff3b
| Author | SHA1 | Date | |
|---|---|---|---|
| f6ff91ff3b | |||
| acac2858c3 | |||
| cd1c99f487 | |||
| 607892173d |
@@ -1,14 +1,14 @@
|
|||||||
<header
|
<header class="immersive-header" [class.immersive-header--compact]="!showHero()">
|
||||||
class="immersive-header"
|
|
||||||
[class.immersive-header--compact]="!showHero()"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="immersive-header__backdrop"
|
class="immersive-header__backdrop"
|
||||||
[style.background-image]="backgroundImageUrl() ? 'url(' + backgroundImageUrl() + ')' : null"
|
[style.background-image]="backgroundImageUrl() ? 'url(' + backgroundImageUrl() + ')' : null"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<div class="immersive-header__content">
|
<div class="immersive-header__content">
|
||||||
<nav class="immersive-header__nav container-xl px-3 px-md-4" aria-label="Navegación de la tienda">
|
<nav
|
||||||
|
class="immersive-header__nav container-xl px-3 px-md-4"
|
||||||
|
aria-label="Navegación de la tienda"
|
||||||
|
>
|
||||||
<a routerLink="/" class="immersive-header__brand" aria-label="Ir al inicio">
|
<a routerLink="/" class="immersive-header__brand" aria-label="Ir al inicio">
|
||||||
@if (logoUrl()) {
|
@if (logoUrl()) {
|
||||||
<img [src]="logoUrl()" alt="Logo del comercio" />
|
<img [src]="logoUrl()" alt="Logo del comercio" />
|
||||||
@@ -19,19 +19,14 @@
|
|||||||
@if (displaySearchBar()) {
|
@if (displaySearchBar()) {
|
||||||
<form class="immersive-header__search" role="search" (submit)="submitSearch($event)">
|
<form class="immersive-header__search" role="search" (submit)="submitSearch($event)">
|
||||||
<label class="visually-hidden" for="immersive-search-input">Buscar productos</label>
|
<label class="visually-hidden" for="immersive-search-input">Buscar productos</label>
|
||||||
<input
|
<app-input
|
||||||
id="immersive-search-input"
|
id="immersive-search-input"
|
||||||
type="search"
|
|
||||||
placeholder="Buscar"
|
placeholder="Buscar"
|
||||||
autocomplete="off"
|
type="search"
|
||||||
[formControl]="searchControl"
|
[(value)]="searchTerm"
|
||||||
[attr.aria-invalid]="showSearchError()"
|
[invalid]="showSearchError()"
|
||||||
[attr.aria-describedby]="showSearchError() ? 'immersive-search-error' : null"
|
(valueChange)="showSearchError.set(false)"
|
||||||
(input)="showSearchError.set(false)"
|
|
||||||
/>
|
/>
|
||||||
<button type="submit" aria-label="Buscar">
|
|
||||||
<i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
@if (showSearchError()) {
|
@if (showSearchError()) {
|
||||||
<span id="immersive-search-error" class="immersive-header__search-error" role="alert"
|
<span id="immersive-search-error" class="immersive-header__search-error" role="alert"
|
||||||
>Ingresá al menos 3 caracteres.</span
|
>Ingresá al menos 3 caracteres.</span
|
||||||
@@ -41,9 +36,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@if (ticketsMenu(); as menu) {
|
@if (ticketsMenu(); as menu) {
|
||||||
<button class="immersive-header__tickets" type="button" (click)="ticketsClick.emit()">
|
<app-button
|
||||||
|
variant="secondary"
|
||||||
|
hostClass="immersive-header__tickets"
|
||||||
|
(click)="ticketsClick.emit()"
|
||||||
|
>
|
||||||
{{ menu.label }}
|
{{ menu.label }}
|
||||||
</button>
|
</app-button>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (displayCart()) {
|
@if (displayCart()) {
|
||||||
@@ -78,7 +77,11 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@if (checkoutRemainingTime(); as remainingTime) {
|
@if (checkoutRemainingTime(); as remainingTime) {
|
||||||
<div class="immersive-header__timer container-xl px-3 px-md-4" role="timer" aria-label="Tiempo restante de compra">
|
<div
|
||||||
|
class="immersive-header__timer container-xl px-3 px-md-4"
|
||||||
|
role="timer"
|
||||||
|
aria-label="Tiempo restante de compra"
|
||||||
|
>
|
||||||
Tiempo restante de compra: <strong>{{ remainingTime }}</strong>
|
Tiempo restante de compra: <strong>{{ remainingTime }}</strong>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,57 +74,19 @@
|
|||||||
|
|
||||||
.immersive-header__search {
|
.immersive-header__search {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
|
||||||
width: clamp(115px, 17vw, 205px);
|
width: clamp(115px, 17vw, 205px);
|
||||||
height: 2rem;
|
|
||||||
border: 1px solid var(--tenant-primary, #ff7006);
|
|
||||||
border-radius: 3px;
|
|
||||||
background: rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.immersive-header__search input {
|
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
color: #fff;
|
|
||||||
background: transparent;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
.immersive-header__search input::placeholder {
|
|
||||||
color: rgba(255, 255, 255, 0.78);
|
|
||||||
}
|
|
||||||
.immersive-header__search input::-webkit-search-cancel-button {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
.immersive-header__search button {
|
|
||||||
border: 0;
|
|
||||||
padding-inline: 0.55rem;
|
|
||||||
color: var(--tenant-primary, #ff7006);
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
.immersive-header__search:focus-within {
|
|
||||||
outline: 2px solid var(--tenant-primary, #ff7006);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
}
|
||||||
.immersive-header__search-error {
|
.immersive-header__search-error {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% + 0.25rem);
|
top: calc(100% + 0.25rem);
|
||||||
right: 0;
|
right: 0;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
color: #fff;
|
color: var(--tenant-danger, #dc3545);
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
}
|
}
|
||||||
.immersive-header__tickets {
|
|
||||||
border: 1px solid var(--tenant-primary, #ff7006);
|
:host ::ng-deep .immersive-header__tickets {
|
||||||
border-radius: 3px;
|
width: auto;
|
||||||
padding: 0.25rem 0.6rem;
|
|
||||||
color: #fff;
|
|
||||||
background: rgba(0, 0, 0, 0.2);
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
.immersive-header__tickets:hover {
|
|
||||||
background: var(--tenant-primary, #ff7006);
|
|
||||||
}
|
}
|
||||||
.immersive-header__account {
|
.immersive-header__account {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -219,9 +181,3 @@
|
|||||||
font-size: clamp(3rem, 12vw, 5rem);
|
font-size: clamp(3rem, 12vw, 5rem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
.immersive-header__tickets {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ import {
|
|||||||
output,
|
output,
|
||||||
signal,
|
signal,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { RouterLink } from '@angular/router';
|
import { RouterLink } from '@angular/router';
|
||||||
import { AuthUser } from '../../../services/auth/auth.interfaces';
|
import { AuthUser } from '../../../services/auth/auth.interfaces';
|
||||||
import { Menu, WebsiteExtras } from '../../../services/tenant.interface';
|
import { Menu, WebsiteExtras } from '../../../services/tenant.interface';
|
||||||
|
import { ButtonComponent } from '../../../../shared/components/button/button.component';
|
||||||
import { CartIconComponent } from '../../../../shared/components/cart-icon/cart-icon.component';
|
import { CartIconComponent } from '../../../../shared/components/cart-icon/cart-icon.component';
|
||||||
import { IconButtonComponent } from '../../../../shared/components/icon-button/icon-button.component';
|
import { IconButtonComponent } from '../../../../shared/components/icon-button/icon-button.component';
|
||||||
|
import { InputComponent } from '../../../../shared/components/input/input.component';
|
||||||
import { ContinuousImageCarouselComponent } from '../../../../shared/components/continuous-image-carousel/continuous-image-carousel.component';
|
import { ContinuousImageCarouselComponent } from '../../../../shared/components/continuous-image-carousel/continuous-image-carousel.component';
|
||||||
import { UserDropdownComponent } from './user-dropdown/user-dropdown.component';
|
import { UserDropdownComponent } from './user-dropdown/user-dropdown.component';
|
||||||
|
|
||||||
@@ -21,9 +22,10 @@ import { UserDropdownComponent } from './user-dropdown/user-dropdown.component';
|
|||||||
selector: 'app-immersive-store-header',
|
selector: 'app-immersive-store-header',
|
||||||
imports: [
|
imports: [
|
||||||
RouterLink,
|
RouterLink,
|
||||||
ReactiveFormsModule,
|
ButtonComponent,
|
||||||
CartIconComponent,
|
CartIconComponent,
|
||||||
IconButtonComponent,
|
IconButtonComponent,
|
||||||
|
InputComponent,
|
||||||
ContinuousImageCarouselComponent,
|
ContinuousImageCarouselComponent,
|
||||||
UserDropdownComponent,
|
UserDropdownComponent,
|
||||||
],
|
],
|
||||||
@@ -54,7 +56,7 @@ export class ImmersiveStoreHeaderComponent {
|
|||||||
readonly logoutClick = output<void>();
|
readonly logoutClick = output<void>();
|
||||||
readonly searchSubmit = output<string>();
|
readonly searchSubmit = output<string>();
|
||||||
|
|
||||||
protected readonly searchControl = new FormControl('', { nonNullable: true });
|
protected searchTerm = '';
|
||||||
protected readonly showSearchError = signal(false);
|
protected readonly showSearchError = signal(false);
|
||||||
protected readonly isUserDropdownOpen = signal(false);
|
protected readonly isUserDropdownOpen = signal(false);
|
||||||
protected readonly checkoutRemainingTime = computed(() => {
|
protected readonly checkoutRemainingTime = computed(() => {
|
||||||
@@ -68,7 +70,7 @@ export class ImmersiveStoreHeaderComponent {
|
|||||||
|
|
||||||
protected submitSearch(event?: Event): void {
|
protected submitSearch(event?: Event): void {
|
||||||
event?.preventDefault();
|
event?.preventDefault();
|
||||||
const term = this.searchControl.value.trim();
|
const term = this.searchTerm.trim();
|
||||||
if (term.length < 3) {
|
if (term.length < 3) {
|
||||||
this.showSearchError.set(true);
|
this.showSearchError.set(true);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
[displaySeachBar]="tenant()?.display_seach_bar ?? true"
|
[displaySeachBar]="tenant()?.display_seach_bar ?? true"
|
||||||
[displayCart]="displayCart()"
|
[displayCart]="displayCart()"
|
||||||
[cartDisabled]="isCheckoutRoute()"
|
[cartDisabled]="isCheckoutRoute()"
|
||||||
[checkoutRemainingSeconds]="checkoutRemainingSeconds()"
|
[checkoutRemainingSeconds]="headerCheckoutRemainingSeconds()"
|
||||||
(cartClick)="onCartClick()"
|
(cartClick)="onCartClick()"
|
||||||
(ticketsClick)="onTicketsClick()"
|
(ticketsClick)="onTicketsClick()"
|
||||||
(loginClick)="onLoginClick()"
|
(loginClick)="onLoginClick()"
|
||||||
|
|||||||
@@ -428,6 +428,26 @@ describe('StoreLayoutComponent', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('moves the countdown out of the header on multi-event checkout', () => {
|
||||||
|
tenantState.set({
|
||||||
|
...tenant,
|
||||||
|
storefront_website_type_code: 'onticket_multi_event',
|
||||||
|
checkout_summary_type: 'event',
|
||||||
|
});
|
||||||
|
checkoutRemainingSecondsState.set(587);
|
||||||
|
const router = TestBed.inject(Router);
|
||||||
|
vi.spyOn(router, 'url', 'get').mockReturnValue('/checkout/25');
|
||||||
|
|
||||||
|
const fixture = TestBed.createComponent(StoreLayoutComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
|
const header = fixture.debugElement.query(By.directive(StoreHeaderComponent));
|
||||||
|
|
||||||
|
expect(header.componentInstance.checkoutRemainingSeconds()).toBeNull();
|
||||||
|
expect(element.querySelector('.store-layout__checkout-timer')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('hides the configured header elements when the tenant disables them', () => {
|
it('hides the configured header elements when the tenant disables them', () => {
|
||||||
tenantState.set({
|
tenantState.set({
|
||||||
...tenant,
|
...tenant,
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ export class StoreLayoutComponent implements OnInit {
|
|||||||
private readonly isMultiEventStorefront = computed(
|
private readonly isMultiEventStorefront = computed(
|
||||||
() => this.tenant()?.storefront_website_type_code === 'onticket_multi_event',
|
() => this.tenant()?.storefront_website_type_code === 'onticket_multi_event',
|
||||||
);
|
);
|
||||||
|
protected readonly headerCheckoutRemainingSeconds = computed(() =>
|
||||||
|
this.isCheckoutRoute() && this.tenant()?.checkout_summary_type === 'event'
|
||||||
|
? null
|
||||||
|
: this.checkoutRemainingSeconds(),
|
||||||
|
);
|
||||||
protected readonly navigationCategories = computed(() =>
|
protected readonly navigationCategories = computed(() =>
|
||||||
this.isMultiEventStorefront()
|
this.isMultiEventStorefront()
|
||||||
? (this.tenant()?.event_categories ?? [])
|
? (this.tenant()?.event_categories ?? [])
|
||||||
|
|||||||
@@ -121,11 +121,17 @@ export interface PurchaseDetailItemResponse {
|
|||||||
nombre: string;
|
nombre: string;
|
||||||
descripcion: string | null;
|
descripcion: string | null;
|
||||||
slug: string;
|
slug: string;
|
||||||
imagen: string | null;
|
imagen?: string | null;
|
||||||
attributes: PurchaseDetailAttributeResponse[];
|
attributes: PurchaseDetailAttributeResponse[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PurchaseCheckoutEventResponse {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
image: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PurchaseDetailResponse extends PurchaseStatusResponse {
|
export interface PurchaseDetailResponse extends PurchaseStatusResponse {
|
||||||
id: number;
|
id: number;
|
||||||
cart_id: number | null;
|
cart_id: number | null;
|
||||||
@@ -140,6 +146,7 @@ export interface PurchaseDetailResponse extends PurchaseStatusResponse {
|
|||||||
email: string | null;
|
email: string | null;
|
||||||
items_source: 'purchase';
|
items_source: 'purchase';
|
||||||
items: PurchaseDetailItemResponse[];
|
items: PurchaseDetailItemResponse[];
|
||||||
|
event?: PurchaseCheckoutEventResponse | null;
|
||||||
tickets_count?: number;
|
tickets_count?: number;
|
||||||
has_generated_tickets?: boolean;
|
has_generated_tickets?: boolean;
|
||||||
subtotal: string;
|
subtotal: string;
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export interface Tenant {
|
|||||||
footer_bg_image?: string | null;
|
footer_bg_image?: string | null;
|
||||||
storefront_website_type_code?: string | null;
|
storefront_website_type_code?: string | null;
|
||||||
header_type?: 'standard' | 'immersive';
|
header_type?: 'standard' | 'immersive';
|
||||||
|
checkout_summary_type?: 'default' | 'event';
|
||||||
extras?: WebsiteExtras;
|
extras?: WebsiteExtras;
|
||||||
event?: TenantEvent | null;
|
event?: TenantEvent | null;
|
||||||
selected_bank_account_id?: number | null;
|
selected_bank_account_id?: number | null;
|
||||||
|
|||||||
@@ -706,7 +706,7 @@
|
|||||||
<app-location-map
|
<app-location-map
|
||||||
[locations]="mapLocations"
|
[locations]="mapLocations"
|
||||||
[markerColor]="tenant()?.primary_color ?? '#24a9e0'"
|
[markerColor]="tenant()?.primary_color ?? '#24a9e0'"
|
||||||
mapStyle="minimal-light"
|
mapStyle="standard"
|
||||||
ariaLabel="Mapa de puntos de atención en Rosario"
|
ariaLabel="Mapa de puntos de atención en Rosario"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export class PurchaseDetailPage implements OnInit {
|
|||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.item_details.nombre || 'Producto sin nombre',
|
title: item.item_details.nombre || 'Producto sin nombre',
|
||||||
description: item.item_details.descripcion,
|
description: item.item_details.descripcion,
|
||||||
imageUrl: item.item_details.imagen,
|
imageUrl: item.item_details.imagen ?? null,
|
||||||
quantity: item.quantity,
|
quantity: item.quantity,
|
||||||
attributes: item.item_details.attributes.map((attribute) => ({
|
attributes: item.item_details.attributes.map((attribute) => ({
|
||||||
label: attribute.name,
|
label: attribute.name,
|
||||||
|
|||||||
@@ -47,7 +47,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="checkout-page__cart-col">
|
<div class="checkout-page__cart-col">
|
||||||
|
@if (usesEventCheckoutSummary()) {
|
||||||
@if (checkoutRemainingTime(); as remainingTime) {
|
@if (checkoutRemainingTime(); as remainingTime) {
|
||||||
|
<div
|
||||||
|
class="checkout-page__summary-countdown d-flex align-items-baseline justify-content-center gap-3"
|
||||||
|
role="timer"
|
||||||
|
aria-label="Tiempo restante de compra"
|
||||||
|
>
|
||||||
|
<span class="checkout-page__summary-countdown-label">Tiempo restante de compra:</span>
|
||||||
|
<span class="checkout-page__summary-countdown-value">{{ remainingTime }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (checkoutEvent(); as event) {
|
||||||
|
@if (event.image) {
|
||||||
|
<div class="checkout-page__event-media">
|
||||||
|
<img [src]="event.image" [alt]="event.title" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} @else if (checkoutRemainingTime(); as remainingTime) {
|
||||||
<div
|
<div
|
||||||
class="checkout-page__mobile-countdown d-flex d-md-none align-items-baseline justify-content-center gap-3"
|
class="checkout-page__mobile-countdown d-flex d-md-none align-items-baseline justify-content-center gap-3"
|
||||||
role="timer"
|
role="timer"
|
||||||
|
|||||||
@@ -46,6 +46,38 @@
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__summary-countdown {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: var(--tenant-primary);
|
||||||
|
font-weight: 700;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__summary-countdown-label {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__summary-countdown-value {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__event-media {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkout-page__loading {
|
.checkout-page__loading {
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ describe('CheckoutPageComponent payment validation', () => {
|
|||||||
let tenantState: ReturnType<
|
let tenantState: ReturnType<
|
||||||
typeof signal<{
|
typeof signal<{
|
||||||
codigo: string;
|
codigo: string;
|
||||||
|
storefront_website_type_code?: string | null;
|
||||||
|
checkout_summary_type?: 'default' | 'event';
|
||||||
checkout_editing_policy?: CartEditingPolicy;
|
checkout_editing_policy?: CartEditingPolicy;
|
||||||
}>
|
}>
|
||||||
>;
|
>;
|
||||||
@@ -468,6 +470,49 @@ describe('CheckoutPageComponent payment validation', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses the event image and removes item images for multi-event checkout', () => {
|
||||||
|
tenantState.set({
|
||||||
|
...tenantState(),
|
||||||
|
checkout_summary_type: 'event',
|
||||||
|
});
|
||||||
|
const { component } = createComponent();
|
||||||
|
component.createdPurchase.set({
|
||||||
|
id: 25,
|
||||||
|
status: 'created',
|
||||||
|
event: {
|
||||||
|
id: 12,
|
||||||
|
title: 'Festival de prueba',
|
||||||
|
image: 'https://example.com/event.jpg',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 91,
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: '10000.00',
|
||||||
|
line_total: '10000.00',
|
||||||
|
source_catalog_item_id: 8,
|
||||||
|
source_variant_id: null,
|
||||||
|
item_details: {
|
||||||
|
nombre: 'Entrada general',
|
||||||
|
descripcion: null,
|
||||||
|
slug: 'entrada-general',
|
||||||
|
imagen: 'https://example.com/product.jpg',
|
||||||
|
attributes: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subtotal: '10000.00',
|
||||||
|
total: '10000.00',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(component.checkoutEvent()).toEqual({
|
||||||
|
id: 12,
|
||||||
|
title: 'Festival de prueba',
|
||||||
|
image: 'https://example.com/event.jpg',
|
||||||
|
});
|
||||||
|
expect(component.mappedCartItems()[0].imageUrl).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps the checkout hidden while the purchase is loading', async () => {
|
it('keeps the checkout hidden while the purchase is loading', async () => {
|
||||||
let resolvePurchase!: (purchase: any) => void;
|
let resolvePurchase!: (purchase: any) => void;
|
||||||
routeParamMap = convertToParamMap({ id: 25 });
|
routeParamMap = convertToParamMap({ id: 25 });
|
||||||
|
|||||||
@@ -138,6 +138,12 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
const purchase = this.createdPurchase();
|
const purchase = this.createdPurchase();
|
||||||
return purchase ? purchase.items.map((item) => this.mapPurchaseItemToMock(item)) : [];
|
return purchase ? purchase.items.map((item) => this.mapPurchaseItemToMock(item)) : [];
|
||||||
});
|
});
|
||||||
|
protected readonly usesEventCheckoutSummary = computed(
|
||||||
|
() => this.tenantService.tenant()?.checkout_summary_type === 'event',
|
||||||
|
);
|
||||||
|
protected readonly checkoutEvent = computed(() =>
|
||||||
|
this.usesEventCheckoutSummary() ? (this.createdPurchase()?.event ?? null) : null,
|
||||||
|
);
|
||||||
|
|
||||||
protected readonly isStep1Valid = signal(this.form.valid);
|
protected readonly isStep1Valid = signal(this.form.valid);
|
||||||
protected readonly paymentMethods: ReadonlyArray<PaymentMethodOption> = [
|
protected readonly paymentMethods: ReadonlyArray<PaymentMethodOption> = [
|
||||||
@@ -235,7 +241,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
|||||||
private mapPurchaseItemToMock(item: PurchaseDetailItemResponse): CartItemMock {
|
private mapPurchaseItemToMock(item: PurchaseDetailItemResponse): CartItemMock {
|
||||||
return {
|
return {
|
||||||
cartItemId: item.id,
|
cartItemId: item.id,
|
||||||
imageUrl: item.item_details.imagen,
|
imageUrl: this.usesEventCheckoutSummary() ? null : (item.item_details.imagen ?? null),
|
||||||
product: item.item_details.nombre,
|
product: item.item_details.nombre,
|
||||||
originalPrice: null,
|
originalPrice: null,
|
||||||
discountedPrice: parseFloat(item.unit_price),
|
discountedPrice: parseFloat(item.unit_price),
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
class="event-detail__map"
|
class="event-detail__map"
|
||||||
[locations]="mapLocations()"
|
[locations]="mapLocations()"
|
||||||
ariaLabel="Ubicación del evento"
|
ariaLabel="Ubicación del evento"
|
||||||
mapStyle="minimal-light"
|
mapStyle="standard"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
.event-detail__description p { margin: 0; white-space: pre-line; line-height: 1.36; font-size: 14px; }
|
.event-detail__description p { margin: 0; white-space: pre-line; line-height: 1.36; font-size: 14px; }
|
||||||
.event-detail__social { display: grid; gap: .35rem; margin-top: 2.3rem; }
|
.event-detail__social { display: grid; gap: .35rem; margin-top: 2.3rem; }
|
||||||
.event-detail__social a { color: #666666; font-family: 'Gotham Book', sans-serif; font-size: 14px; font-weight: 400; display: flex; align-items: center; gap: .5rem; text-decoration: none; font-style: italic; }
|
.event-detail__social a { color: #666666; font-family: 'Gotham Book', sans-serif; font-size: 14px; font-weight: 400; display: flex; align-items: center; gap: .5rem; text-decoration: none; font-style: italic; }
|
||||||
.event-detail__social a:hover { color: var(--tenant-primary); text-decoration: underline; }
|
.event-detail__social a:hover { color: var(--tenant-primary); text-decoration: none; }
|
||||||
.event-detail__social i { width: 14px; font-size: 14px; text-align: center; }
|
.event-detail__social i { width: 18px; height: 18px; font-size: 18px; line-height: 18px; text-align: center; }
|
||||||
.event-detail__map { margin-top: 16px; --location-map-min-height: 180px; --location-map-border-radius: 0; }
|
.event-detail__map { margin-top: 16px; --location-map-min-height: 180px; --location-map-border-radius: 0; }
|
||||||
.event-detail__header { margin-bottom: 2rem; padding-top: .7rem; }
|
.event-detail__header { margin-bottom: 2rem; padding-top: .7rem; }
|
||||||
.event-detail__header h1 { margin: 0; color: #666666; font-size: 24px; line-height: 1.25; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; }
|
.event-detail__header h1 { margin: 0; color: #666666; font-size: 24px; line-height: 1.25; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; }
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
class="contact-page__map"
|
class="contact-page__map"
|
||||||
[locations]="contact().mapLocations"
|
[locations]="contact().mapLocations"
|
||||||
[markerColor]="markerColor()"
|
[markerColor]="markerColor()"
|
||||||
mapStyle="minimal-light"
|
mapStyle="standard"
|
||||||
ariaLabel="Mapa de sucursales y puntos de atención"
|
ariaLabel="Mapa de sucursales y puntos de atención"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ describe('ContactPage', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(map).not.toBeNull();
|
expect(map).not.toBeNull();
|
||||||
expect(map?.getAttribute('mapstyle')).toBe('minimal-light');
|
expect(map?.getAttribute('mapstyle')).toBe('standard');
|
||||||
expect(accessibleLocations).toHaveLength(2);
|
expect(accessibleLocations).toHaveLength(2);
|
||||||
expect(map?.textContent).toContain('Gigante de Arroyito');
|
expect(map?.textContent).toContain('Gigante de Arroyito');
|
||||||
expect(map?.textContent).toContain('Telepagos');
|
expect(map?.textContent).toContain('Telepagos');
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import type { LayerGroup, Map as LeafletMap, LatLngBounds, LatLngTuple, TileLayer } from 'leaflet';
|
import type { LayerGroup, Map as LeafletMap, LatLngBounds, LatLngTuple, TileLayer } from 'leaflet';
|
||||||
|
|
||||||
export type MapStyle = 'minimal-light' | 'standard';
|
export type MapStyle = 'standard';
|
||||||
|
|
||||||
const MAP_LAYERS: Record<
|
const MAP_LAYERS: Record<
|
||||||
MapStyle,
|
MapStyle,
|
||||||
@@ -23,12 +23,6 @@ const MAP_LAYERS: Record<
|
|||||||
maxZoom: number;
|
maxZoom: number;
|
||||||
}
|
}
|
||||||
> = {
|
> = {
|
||||||
'minimal-light': {
|
|
||||||
url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',
|
|
||||||
attribution:
|
|
||||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
|
||||||
maxZoom: 20,
|
|
||||||
},
|
|
||||||
standard: {
|
standard: {
|
||||||
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
attribution:
|
attribution:
|
||||||
@@ -56,7 +50,7 @@ export class LocationMapComponent implements AfterViewInit, OnChanges, OnDestroy
|
|||||||
@Input() fallbackCenter: LatLngTuple = [-32.94682, -60.63932];
|
@Input() fallbackCenter: LatLngTuple = [-32.94682, -60.63932];
|
||||||
@Input() fallbackZoom = 13;
|
@Input() fallbackZoom = 13;
|
||||||
@Input() maxFitZoom = 15;
|
@Input() maxFitZoom = 15;
|
||||||
@Input() mapStyle: MapStyle = 'minimal-light';
|
@Input() mapStyle: MapStyle = 'standard';
|
||||||
@Input() markerColor = '#24a9e0';
|
@Input() markerColor = '#24a9e0';
|
||||||
|
|
||||||
@ViewChild('mapContainer', { static: true })
|
@ViewChild('mapContainer', { static: true })
|
||||||
|
|||||||
Reference in New Issue
Block a user