diff --git a/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.html b/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.html
new file mode 100644
index 0000000..c290a5d
--- /dev/null
+++ b/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.html
@@ -0,0 +1,9 @@
+
+ @if (event().image; as image) {
+
+ }
+
+
+ {{ event().title }}
+
+
diff --git a/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.scss b/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.scss
new file mode 100644
index 0000000..8be7147
--- /dev/null
+++ b/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.scss
@@ -0,0 +1,24 @@
+:host {
+ display: block;
+}
+
+.ticket-event-context {
+ padding-top: 1.5rem;
+ border-top: 1px solid var(--border-color);
+}
+
+.ticket-event-context__image {
+ display: block;
+ width: 100%;
+ height: auto;
+ border-radius: 4px;
+}
+
+.ticket-event-context__title {
+ margin: 1rem 0 0;
+ color: #666666;
+ font-size: 13px;
+ font-weight: 700;
+ line-height: 1.4;
+ text-transform: uppercase;
+}
diff --git a/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.ts b/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.ts
new file mode 100644
index 0000000..d4df605
--- /dev/null
+++ b/src/app/features/store/pages/account-page/pages/tickets-page/components/ticket-event-context/ticket-event-context.component.ts
@@ -0,0 +1,15 @@
+import { Component, input } from '@angular/core';
+
+export interface TicketEventContext {
+ title: string;
+ image: string | null;
+}
+
+@Component({
+ selector: 'app-ticket-event-context',
+ templateUrl: './ticket-event-context.component.html',
+ styleUrl: './ticket-event-context.component.scss',
+})
+export class TicketEventContextComponent {
+ readonly event = input.required();
+}
diff --git a/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.html b/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.html
index 55f990b..953287e 100644
--- a/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.html
+++ b/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.html
@@ -109,3 +109,9 @@
}
+
+@if (eventId !== undefined) {
+
+
+
+}
diff --git a/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.spec.ts b/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.spec.ts
index 63223c7..c73cbd1 100644
--- a/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.spec.ts
+++ b/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.spec.ts
@@ -1,18 +1,22 @@
import { signal } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TestBed } from '@angular/core/testing';
+import { ActivatedRoute } from '@angular/router';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { TenantService } from '../../../../../../core/services/tenant.service';
import { ToastService } from '../../../../../../core/services/toast.service';
import { ModalService } from '../../../../../../core/services/modal.service';
+import { MenuPageSidebarContentService } from '../../../../components/menu-page-layout/menu-page-sidebar-content.service';
import { TicketComponent } from './components/ticket/ticket.component';
import { TicketResponse, TicketService } from './ticket.service';
import { TicketsPage } from './tickets-page';
function withCustomLoading(service: T): T & { withCustomLoading: () => T } {
- return Object.assign(service, {
- withCustomLoading: () => service,
+ const enhancedService = Object.assign({ getTicketEvents: () => Promise.resolve([]) }, service);
+
+ return Object.assign(enhancedService, {
+ withCustomLoading: () => enhancedService,
});
}
@@ -300,4 +304,69 @@ describe('TicketsPage', () => {
ticket: 'ticket-1',
});
});
+
+ it('declares contextual test data when tickets belong to an event', async () => {
+ const getTickets = vi.fn().mockResolvedValue([]);
+ const getTicketEvents = vi.fn().mockResolvedValue([
+ {
+ id: 42,
+ title: 'XX Campeonato Mundial de Pelota Vasca',
+ image: 'https://example.com/pelota-vasca.jpg',
+ },
+ ]);
+
+ await TestBed.configureTestingModule({
+ imports: [TicketsPage],
+ providers: [
+ MenuPageSidebarContentService,
+ { provide: ToastService, useValue: { danger: vi.fn() } },
+ {
+ provide: ActivatedRoute,
+ useValue: { snapshot: { paramMap: { get: () => '42' } } },
+ },
+ ],
+ })
+ .overrideComponent(TicketsPage, {
+ set: {
+ providers: [
+ {
+ provide: TicketService,
+ useValue: withCustomLoading({ getTickets, getTicketEvents }),
+ },
+ ],
+ },
+ })
+ .compileComponents();
+
+ const fixture = TestBed.createComponent(TicketsPage);
+ fixture.detectChanges();
+ await fixture.whenStable();
+ await vi.waitFor(() => expect(getTicketEvents).toHaveBeenCalledOnce());
+ await vi.waitFor(() =>
+ expect(
+ (
+ fixture.componentInstance as unknown as { eventContext: () => { image: string | null } }
+ ).eventContext().image,
+ ).toBe('https://example.com/pelota-vasca.jpg'),
+ );
+
+ const sidebarContent = TestBed.inject(MenuPageSidebarContentService);
+ const sidebarView = sidebarContent.template()?.createEmbeddedView({});
+ sidebarView?.detectChanges();
+
+ const container = document.createElement('div');
+ sidebarView?.rootNodes.forEach((node) => container.appendChild(node));
+
+ expect(getTickets).toHaveBeenCalledWith(42);
+ expect(container.querySelector('.ticket-event-context')?.textContent).toContain(
+ 'XX Campeonato Mundial de Pelota Vasca',
+ );
+ expect(container.querySelector('.ticket-event-context__image')?.src).toBe(
+ 'https://example.com/pelota-vasca.jpg',
+ );
+ expect(container.querySelector('.ticket-event-context__details')).toBeNull();
+ expect(container.querySelector('.ticket-event-context__recommendation')).toBeNull();
+
+ sidebarView?.destroy();
+ });
});
diff --git a/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.ts b/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.ts
index 246156a..92ccff8 100644
--- a/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.ts
+++ b/src/app/features/store/pages/account-page/pages/tickets-page/tickets-page.ts
@@ -5,12 +5,23 @@ import { ModalService } from '../../../../../../core/services/modal.service';
import { ToastService } from '../../../../../../core/services/toast.service';
import { IconButtonComponent } from '../../../../../../shared/components/icon-button/icon-button.component';
import { MenuContentSectionComponent } from '../../../../components/menu-content-section/menu-content-section.component';
+import { MenuPageSidebarContentDirective } from '../../../../components/menu-page-layout/menu-page-sidebar-content.directive';
+import {
+ TicketEventContext,
+ TicketEventContextComponent,
+} from './components/ticket-event-context/ticket-event-context.component';
import { TicketComponent } from './components/ticket/ticket.component';
import { TicketResponse, TicketService } from './ticket.service';
@Component({
selector: 'app-tickets-page',
- imports: [IconButtonComponent, TicketComponent, MenuContentSectionComponent],
+ imports: [
+ IconButtonComponent,
+ TicketComponent,
+ TicketEventContextComponent,
+ MenuContentSectionComponent,
+ MenuPageSidebarContentDirective,
+ ],
providers: [TicketService],
templateUrl: './tickets-page.html',
styleUrl: './tickets-page.scss',
@@ -21,6 +32,11 @@ export class TicketsPage implements OnInit {
private readonly modalService = inject(ModalService);
private readonly route = inject(ActivatedRoute, { optional: true });
+ protected readonly eventId = this.eventIdFromRoute();
+ protected readonly eventContext = signal({
+ title: 'XX Campeonato Mundial de Pelota Vasca',
+ image: null,
+ });
protected readonly tickets = signal([]);
protected readonly activeTickets = computed(() =>
this.tickets().filter((ticket) => !this.isInactive(ticket)),
@@ -38,9 +54,25 @@ export class TicketsPage implements OnInit {
async ngOnInit(): Promise {
try {
- this.tickets.set(
- await this.ticketService.withCustomLoading().getTickets(this.eventIdFromRoute()),
- );
+ const service = this.ticketService.withCustomLoading();
+ this.tickets.set(await service.getTickets(this.eventId));
+
+ if (this.eventId !== undefined) {
+ void service
+ .getTicketEvents()
+ .then((events) => {
+ const event = events.find((candidate) => candidate.id === this.eventId);
+
+ if (event) {
+ this.eventContext.update((context) => ({
+ ...context,
+ title: event.title,
+ image: event.image,
+ }));
+ }
+ })
+ .catch(() => undefined);
+ }
} catch {
this.toastService.danger('Hubo un error al cargar los tickets');
} finally {