feat: refactor menu content section for improved structure and responsiveness across account and help pages
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
<section class="menu-content-section" [attr.aria-labelledby]="titleId()">
|
<section class="menu-content-section" [attr.aria-labelledby]="titleId()">
|
||||||
<h2 class="menu-content-section__title" [id]="titleId()">{{ title() }}</h2>
|
<header class="menu-content-section__header">
|
||||||
|
<div class="menu-content-section__prefix">
|
||||||
|
<ng-content select="[menuContentPrefix]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="menu-content-section__title" [id]="titleId()">
|
||||||
|
{{ title() | uppercase }}
|
||||||
|
</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
<div class="menu-content-section__body">
|
<div class="menu-content-section__body">
|
||||||
<ng-content />
|
<ng-content />
|
||||||
|
|||||||
@@ -8,8 +8,19 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-content-section__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-content-section__prefix:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-content-section__title {
|
.menu-content-section__title {
|
||||||
margin: 0 0 1.25rem;
|
margin: 0;
|
||||||
color: #888888;
|
color: #888888;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -25,7 +36,18 @@
|
|||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menu-content-section__header {
|
||||||
|
position: relative;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-content-section__prefix:not(:empty) {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-content-section__title {
|
.menu-content-section__title {
|
||||||
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, signal } from '@angular/core';
|
||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import { Tenant } from '../../../../core/services/tenant.interface';
|
||||||
|
import { TenantService } from '../../../../core/services/tenant.service';
|
||||||
import { MenuContentSectionComponent } from './menu-content-section.component';
|
import { MenuContentSectionComponent } from './menu-content-section.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
imports: [MenuContentSectionComponent],
|
imports: [MenuContentSectionComponent],
|
||||||
template: `
|
template: `
|
||||||
<app-menu-content-section title="Contacto" titleId="contact-title">
|
<app-menu-content-section menuCode="help.contact" titleId="contact-title">
|
||||||
|
<a menuContentPrefix href="/ayuda">Volver</a>
|
||||||
<p>Contenido proyectado</p>
|
<p>Contenido proyectado</p>
|
||||||
</app-menu-content-section>
|
</app-menu-content-section>
|
||||||
`,
|
`,
|
||||||
@@ -16,7 +19,24 @@ class TestHostComponent {}
|
|||||||
|
|
||||||
describe('MenuContentSectionComponent', () => {
|
describe('MenuContentSectionComponent', () => {
|
||||||
it('renders an accessible title and projects its content', async () => {
|
it('renders an accessible title and projects its content', async () => {
|
||||||
await TestBed.configureTestingModule({ imports: [TestHostComponent] }).compileComponents();
|
const tenant = signal({
|
||||||
|
menues: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
code: 'help.contact',
|
||||||
|
label: 'Contacto del comercio',
|
||||||
|
parent_menu_code: 'help',
|
||||||
|
content_type: 'static',
|
||||||
|
route: '/ayuda/contacto',
|
||||||
|
submenues: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as unknown as Tenant);
|
||||||
|
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [TestHostComponent],
|
||||||
|
providers: [{ provide: TenantService, useValue: { tenant: tenant.asReadonly() } }],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
const fixture = TestBed.createComponent(TestHostComponent);
|
const fixture = TestBed.createComponent(TestHostComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -25,7 +45,12 @@ describe('MenuContentSectionComponent', () => {
|
|||||||
const section = element.querySelector('section');
|
const section = element.querySelector('section');
|
||||||
|
|
||||||
expect(section?.getAttribute('aria-labelledby')).toBe('contact-title');
|
expect(section?.getAttribute('aria-labelledby')).toBe('contact-title');
|
||||||
expect(element.querySelector('#contact-title')?.textContent?.trim()).toBe('Contacto');
|
expect(element.querySelector('#contact-title')?.textContent?.trim()).toBe(
|
||||||
|
'CONTACTO DEL COMERCIO',
|
||||||
|
);
|
||||||
|
expect(element.querySelector('.menu-content-section__prefix a')?.textContent).toContain(
|
||||||
|
'Volver',
|
||||||
|
);
|
||||||
expect(element.querySelector('.menu-content-section__body')?.textContent).toContain(
|
expect(element.querySelector('.menu-content-section__body')?.textContent).toContain(
|
||||||
'Contenido proyectado',
|
'Contenido proyectado',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
import { Component, input } from '@angular/core';
|
import { UpperCasePipe } from '@angular/common';
|
||||||
|
import { Component, computed, inject, input } from '@angular/core';
|
||||||
|
|
||||||
|
import { findMenu } from '../../../../core/services/menu.utils';
|
||||||
|
import { TenantService } from '../../../../core/services/tenant.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-menu-content-section',
|
selector: 'app-menu-content-section',
|
||||||
|
imports: [UpperCasePipe],
|
||||||
templateUrl: './menu-content-section.component.html',
|
templateUrl: './menu-content-section.component.html',
|
||||||
styleUrl: './menu-content-section.component.scss',
|
styleUrl: './menu-content-section.component.scss',
|
||||||
})
|
})
|
||||||
export class MenuContentSectionComponent {
|
export class MenuContentSectionComponent {
|
||||||
readonly title = input.required<string>();
|
private readonly tenantService = inject(TenantService);
|
||||||
|
|
||||||
|
readonly menuCode = input.required<string>();
|
||||||
readonly titleId = input.required<string>();
|
readonly titleId = input.required<string>();
|
||||||
|
|
||||||
|
protected readonly title = computed(
|
||||||
|
() => findMenu(this.tenantService.tenant()?.menues ?? [], this.menuCode())?.label ?? '',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,3 +13,13 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.form-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<div class="page-container">
|
<app-menu-content-section
|
||||||
<h2 class="page-title">DATOS PERSONALES</h2>
|
class="account-page"
|
||||||
<app-profile-form></app-profile-form>
|
menuCode="account.profile"
|
||||||
</div>
|
titleId="profile-page-title"
|
||||||
|
>
|
||||||
|
<app-profile-form />
|
||||||
|
</app-menu-content-section>
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
.page-container {
|
:host {
|
||||||
display: flex;
|
display: block;
|
||||||
flex-direction: column;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-page {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #A0A0A0;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { MenuContentSectionComponent } from '../../../../components/menu-content-section/menu-content-section.component';
|
||||||
import { ProfileForm } from '../../components/profile-form/profile-form';
|
import { ProfileForm } from '../../components/profile-form/profile-form';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-profile-page',
|
selector: 'app-profile-page',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [ProfileForm],
|
imports: [ProfileForm, MenuContentSectionComponent],
|
||||||
templateUrl: './profile-page.html',
|
templateUrl: './profile-page.html',
|
||||||
styleUrl: './profile-page.scss',
|
styleUrl: './profile-page.scss',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,26 +1,35 @@
|
|||||||
<div class="page-container">
|
<app-menu-content-section
|
||||||
<div class="d-flex align-items-center mb-4">
|
class="account-page"
|
||||||
<a routerLink="../" class="text-decoration-none " >
|
menuCode="account.purchases"
|
||||||
<i class="bi bi-arrow-left fs-5"></i>
|
titleId="purchase-detail-page-title"
|
||||||
</a>
|
>
|
||||||
<h2 class="page-title m-0">MIS COMPRAS</h2>
|
<a
|
||||||
</div>
|
menuContentPrefix
|
||||||
|
routerLink="../"
|
||||||
|
class="purchase-back-link text-decoration-none"
|
||||||
|
aria-label="Volver a mis compras"
|
||||||
|
>
|
||||||
|
<i class="bi bi-arrow-left fs-5" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
@if (isLoading()) {
|
@if (isLoading()) {
|
||||||
<p class="purchase-loading">Cargando detalle de compra...</p>
|
<p class="purchase-loading">Cargando detalle de compra...</p>
|
||||||
} @else if (purchase(); as purchase) {
|
} @else if (purchase(); as purchase) {
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4 pb-3" style="border-bottom: 1px solid #dddddd;">
|
<div
|
||||||
|
class="d-flex justify-content-between align-items-center mb-4 pb-3"
|
||||||
|
style="border-bottom: 1px solid #dddddd"
|
||||||
|
>
|
||||||
<div class="purchase-info">
|
<div class="purchase-info">
|
||||||
<span class="purchase-id">Compra {{ purchase.id }}.</span>
|
<span class="purchase-id">Compra {{ purchase.id }}.</span>
|
||||||
<span class="purchase-date">Fecha de compra: {{ purchase.date }}</span>
|
<span class="purchase-date">Fecha de compra: {{ purchase.date }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="purchase-total ">
|
<div class="purchase-total">
|
||||||
<span class="purchase-total-label">Total:</span>
|
<span class="purchase-total-label">Total:</span>
|
||||||
<span class="purchase-total-value">${{ purchase.total }}</span>
|
<span class="purchase-total-value">${{ purchase.total }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p style="font-size: 12px; color: #666666; margin:0;">Productos:</p>
|
<p style="font-size: 12px; color: #666666; margin: 0">Productos:</p>
|
||||||
|
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
@for (item of purchase.items; track item.id) {
|
@for (item of purchase.items; track item.id) {
|
||||||
@@ -30,4 +39,4 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</app-menu-content-section>
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
.page-container {
|
:host {
|
||||||
display: flex;
|
display: block;
|
||||||
flex-direction: column;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-page {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
.purchase-back-link {
|
||||||
font-size: 15px;
|
color: #888888;
|
||||||
font-weight: bold;
|
|
||||||
color: #A0A0A0;
|
&:hover,
|
||||||
|
&:focus-visible {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.purchase-info {
|
.purchase-info {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from '../../../../../../core/services/checkout.service';
|
} from '../../../../../../core/services/checkout.service';
|
||||||
import { TenantService } from '../../../../../../core/services/tenant.service';
|
import { TenantService } from '../../../../../../core/services/tenant.service';
|
||||||
import { ToastService } from '../../../../../../core/services/toast.service';
|
import { ToastService } from '../../../../../../core/services/toast.service';
|
||||||
|
import { MenuContentSectionComponent } from '../../../../components/menu-content-section/menu-content-section.component';
|
||||||
import { PurchaseItem, PurchaseItemViewModel } from '../../components/purchase-item/purchase-item';
|
import { PurchaseItem, PurchaseItemViewModel } from '../../components/purchase-item/purchase-item';
|
||||||
|
|
||||||
type PurchaseDetailViewModel = {
|
type PurchaseDetailViewModel = {
|
||||||
@@ -20,7 +21,7 @@ type PurchaseDetailViewModel = {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-purchase-detail-page',
|
selector: 'app-purchase-detail-page',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, RouterLink, PurchaseItem],
|
imports: [CommonModule, RouterLink, PurchaseItem, MenuContentSectionComponent],
|
||||||
templateUrl: './purchase-detail-page.html',
|
templateUrl: './purchase-detail-page.html',
|
||||||
styleUrl: './purchase-detail-page.scss',
|
styleUrl: './purchase-detail-page.scss',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<div class="page-container">
|
<app-menu-content-section
|
||||||
<h2 class="page-title">MIS COMPRAS</h2>
|
class="account-page"
|
||||||
<app-purchase-list></app-purchase-list>
|
menuCode="account.purchases"
|
||||||
</div>
|
titleId="purchases-page-title"
|
||||||
|
>
|
||||||
|
<app-purchase-list />
|
||||||
|
</app-menu-content-section>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
.page-container {
|
:host {
|
||||||
display: flex;
|
display: block;
|
||||||
flex-direction: column;
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-page {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #A0A0A0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { MenuContentSectionComponent } from '../../../../components/menu-content-section/menu-content-section.component';
|
||||||
import { PurchaseList } from '../../components/purchase-list/purchase-list';
|
import { PurchaseList } from '../../components/purchase-list/purchase-list';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-purchases-page',
|
selector: 'app-purchases-page',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [PurchaseList],
|
imports: [PurchaseList, MenuContentSectionComponent],
|
||||||
templateUrl: './purchases-page.html',
|
templateUrl: './purchases-page.html',
|
||||||
styleUrl: './purchases-page.scss',
|
styleUrl: './purchases-page.scss',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<section class="tickets-page">
|
<app-menu-content-section
|
||||||
<h1 class="tickets-page__title">MIS TICKETS</h1>
|
class="tickets-page"
|
||||||
|
menuCode="account.tickets"
|
||||||
|
titleId="tickets-page-title"
|
||||||
|
>
|
||||||
<div class="tickets-list" [attr.aria-busy]="isLoading() || isGeneratingPdf()">
|
<div class="tickets-list" [attr.aria-busy]="isLoading() || isGeneratingPdf()">
|
||||||
@if (isGeneratingPdf()) {
|
@if (isGeneratingPdf()) {
|
||||||
<div class="tickets-list__generating" role="status" aria-live="polite">
|
<div class="tickets-list__generating" role="status" aria-live="polite">
|
||||||
@@ -106,4 +108,4 @@
|
|||||||
<p class="tickets-list__empty">Aún no tenés tickets disponibles.</p>
|
<p class="tickets-list__empty">Aún no tenés tickets disponibles.</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</app-menu-content-section>
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
.tickets-page {
|
.tickets-page {
|
||||||
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 720px;
|
max-width: 720px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tickets-page__title {
|
|
||||||
margin: 0 0 20px;
|
|
||||||
color: #a0a0a0;
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tickets-list {
|
.tickets-list {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@@ -206,10 +200,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767.98px) {
|
@media (max-width: 767.98px) {
|
||||||
.tickets-page__title {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tickets-list__skeleton {
|
.tickets-list__skeleton {
|
||||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
|
import { signal } from '@angular/core';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { TestBed } from '@angular/core/testing';
|
import { TestBed } from '@angular/core/testing';
|
||||||
import { describe, expect, it, vi } from 'vitest';
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
import { TenantService } from '../../../../../../core/services/tenant.service';
|
||||||
import { ToastService } from '../../../../../../core/services/toast.service';
|
import { ToastService } from '../../../../../../core/services/toast.service';
|
||||||
import { ModalService } from '../../../../../../core/services/modal.service';
|
import { ModalService } from '../../../../../../core/services/modal.service';
|
||||||
import { TicketComponent } from './components/ticket/ticket.component';
|
import { TicketComponent } from './components/ticket/ticket.component';
|
||||||
import { TicketResponse, TicketService } from './ticket.service';
|
import { TicketResponse, TicketService } from './ticket.service';
|
||||||
import { TicketsPage } from './tickets-page';
|
import { TicketsPage } from './tickets-page';
|
||||||
|
|
||||||
function withCustomLoading<T extends object>(
|
function withCustomLoading<T extends object>(service: T): T & { withCustomLoading: () => T } {
|
||||||
service: T,
|
|
||||||
): T & { withCustomLoading: () => T } {
|
|
||||||
return Object.assign(service, {
|
return Object.assign(service, {
|
||||||
withCustomLoading: () => service,
|
withCustomLoading: () => service,
|
||||||
});
|
});
|
||||||
@@ -34,6 +34,31 @@ const ticket = (overrides: Partial<TicketResponse>): TicketResponse => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('TicketsPage', () => {
|
describe('TicketsPage', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: TenantService,
|
||||||
|
useValue: {
|
||||||
|
tenant: signal({
|
||||||
|
menues: [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
code: 'account.tickets',
|
||||||
|
label: 'Entradas disponibles',
|
||||||
|
parent_menu_code: 'account',
|
||||||
|
content_type: 'dynamic',
|
||||||
|
route: '/mi-cuenta/tickets',
|
||||||
|
submenues: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).asReadonly(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('shares the generated PDF as a file without text that Windows could prioritize', async () => {
|
it('shares the generated PDF as a file without text that Windows could prioritize', async () => {
|
||||||
const share = vi.fn().mockResolvedValue(undefined);
|
const share = vi.fn().mockResolvedValue(undefined);
|
||||||
const canShare = vi.fn().mockReturnValue(true);
|
const canShare = vi.fn().mockReturnValue(true);
|
||||||
@@ -92,11 +117,11 @@ describe('TicketsPage', () => {
|
|||||||
const createObjectUrl = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:ticket');
|
const createObjectUrl = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:ticket');
|
||||||
const revokeObjectUrl = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined);
|
const revokeObjectUrl = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined);
|
||||||
let downloadedFilename = '';
|
let downloadedFilename = '';
|
||||||
const linkClick = vi
|
const linkClick = vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(function (
|
||||||
.spyOn(HTMLAnchorElement.prototype, 'click')
|
this: HTMLAnchorElement,
|
||||||
.mockImplementation(function (this: HTMLAnchorElement) {
|
) {
|
||||||
downloadedFilename = this.download;
|
downloadedFilename = this.download;
|
||||||
});
|
});
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [TicketsPage],
|
imports: [TicketsPage],
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import { Component, computed, inject, OnInit, signal } from '@angular/core';
|
|||||||
import { ModalService } from '../../../../../../core/services/modal.service';
|
import { ModalService } from '../../../../../../core/services/modal.service';
|
||||||
import { ToastService } from '../../../../../../core/services/toast.service';
|
import { ToastService } from '../../../../../../core/services/toast.service';
|
||||||
import { IconButtonComponent } from '../../../../../../shared/components/icon-button/icon-button.component';
|
import { IconButtonComponent } from '../../../../../../shared/components/icon-button/icon-button.component';
|
||||||
|
import { MenuContentSectionComponent } from '../../../../components/menu-content-section/menu-content-section.component';
|
||||||
import { TicketComponent } from './components/ticket/ticket.component';
|
import { TicketComponent } from './components/ticket/ticket.component';
|
||||||
import { TicketResponse, TicketService } from './ticket.service';
|
import { TicketResponse, TicketService } from './ticket.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tickets-page',
|
selector: 'app-tickets-page',
|
||||||
imports: [IconButtonComponent, TicketComponent],
|
imports: [IconButtonComponent, TicketComponent, MenuContentSectionComponent],
|
||||||
providers: [TicketService],
|
providers: [TicketService],
|
||||||
templateUrl: './tickets-page.html',
|
templateUrl: './tickets-page.html',
|
||||||
styleUrl: './tickets-page.scss',
|
styleUrl: './tickets-page.scss',
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex: 1 1 290px;
|
flex: 1 1 290px;
|
||||||
max-width: 290px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<app-menu-content-section title="CONTACTO" titleId="contact-page-title">
|
<app-menu-content-section menuCode="help.contact" titleId="contact-page-title">
|
||||||
<div class="contact-page">
|
<div class="contact-page">
|
||||||
<div class="contact-page__details">
|
<div class="contact-page__details">
|
||||||
@if (contact().whatsappUrl && contact().whatsappLabel) {
|
@if (contact().whatsappUrl && contact().whatsappLabel) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<app-menu-content-section class="faq-page" title="PREGUNTAS FRECUENTES" titleId="faq-page-title">
|
<app-menu-content-section class="faq-page" menuCode="help.faq" titleId="faq-page-title">
|
||||||
@if (faqs().length > 0) {
|
@if (faqs().length > 0) {
|
||||||
<app-accordion [flush]="true">
|
<app-accordion [flush]="true">
|
||||||
@for (faq of faqs(); track $index; let last = $last) {
|
@for (faq of faqs(); track $index; let last = $last) {
|
||||||
|
|||||||
Reference in New Issue
Block a user