feat(ticket): enhance ticket component with disabled and expired states, update styles and tests

This commit is contained in:
2026-07-21 14:25:52 -03:00
parent 6c5e10feb2
commit fa8032c557
5 changed files with 84 additions and 9 deletions

View File

@@ -1,4 +1,4 @@
<article class="ticket">
<article class="ticket" [class.ticket--disabled]="disabled()" [attr.aria-disabled]="disabled()">
<label class="ticket__selection">
<input
type="checkbox"
@@ -13,17 +13,35 @@
<p class="ticket__id">ID: {{ ticketId() }}</p>
</div>
@if (date(); as ticketDate) {
<time class="ticket__date">{{ ticketDate }}</time>
@if (date() || expired()) {
<div class="ticket__status">
@if (expired()) {
<span class="ticket__expired">VENCIDO</span>
}
@if (date(); as ticketDate) {
<time class="ticket__date">{{ ticketDate }}</time>
}
</div>
}
<div class="ticket__actions">
<app-button variant="primary" buttonClass="ticket__qr-button" (click)="viewQr.emit()">
<app-button
variant="primary"
buttonClass="ticket__qr-button"
[disabled]="disabled()"
(click)="viewQr.emit()"
>
<i class="fa-solid fa-qrcode" aria-hidden="true"></i>
<span>Ver QR</span>
</app-button>
<app-icon-button variant="download" ariaLabel="Descargar ticket" (clicked)="download.emit()" />
<app-icon-button variant="share" ariaLabel="Compartir ticket" (clicked)="share.emit()" />
@if (!disabled()) {
<app-icon-button
variant="download"
ariaLabel="Descargar ticket"
(clicked)="download.emit()"
/>
<app-icon-button variant="share" ariaLabel="Compartir ticket" (clicked)="share.emit()" />
}
</div>
</article>

View File

@@ -48,16 +48,30 @@
}
.ticket__id {
margin-top: 3px;
font-size: 12px;
line-height: 1.4;
}
.ticket__date {
display: block;
font-size: 10px;
line-height: 1.4;
white-space: nowrap;
}
.ticket__status {
text-align: center;
}
.ticket__expired {
display: block;
font-size: 10px;
font-weight: 700;
line-height: 1.4;
text-transform: uppercase;
}
.ticket__actions {
display: flex;
align-items: center;
@@ -72,6 +86,17 @@
padding-inline: 14px;
}
.ticket--disabled {
color: #8a8a8a;
}
:host ::ng-deep .ticket--disabled button.ticket__qr-button:disabled {
--bs-btn-disabled-bg: #8a8a8a;
--bs-btn-disabled-border-color: #8a8a8a;
--bs-btn-disabled-color: #ffffff;
--bs-btn-disabled-opacity: 1;
}
.ticket__selection input:focus-visible {
outline: 2px solid var(--tenant-primary, #009933);
outline-offset: 2px;
@@ -83,7 +108,7 @@
gap: 10px;
}
.ticket__date {
.ticket__status {
grid-column: 2;
}

View File

@@ -32,4 +32,32 @@ describe('TicketComponent', () => {
expect(download).toHaveBeenCalledOnce();
expect(share).toHaveBeenCalledOnce();
});
it('renders the expired disabled state without secondary actions', async () => {
await TestBed.configureTestingModule({ imports: [TicketComponent] }).compileComponents();
const fixture = TestBed.createComponent(TicketComponent);
fixture.componentRef.setInput('ticketId', '0000000000');
fixture.componentRef.setInput('date', '09 de octubre');
fixture.componentRef.setInput('disabled', true);
fixture.componentRef.setInput('expired', true);
const viewQr = vi.fn();
fixture.componentInstance.viewQr.subscribe(viewQr);
fixture.detectChanges();
const element = fixture.nativeElement as HTMLElement;
const ticket = element.querySelector<HTMLElement>('.ticket');
const qrButton = element.querySelector<HTMLButtonElement>('app-button button');
expect(ticket?.classList.contains('ticket--disabled')).toBe(true);
expect(ticket?.getAttribute('aria-disabled')).toBe('true');
expect(element.textContent).toContain('VENCIDO');
expect(qrButton?.disabled).toBe(true);
expect(element.querySelector('[aria-label="Descargar ticket"]')).toBeNull();
expect(element.querySelector('[aria-label="Compartir ticket"]')).toBeNull();
qrButton?.click();
expect(viewQr).not.toHaveBeenCalled();
});
});

View File

@@ -12,8 +12,10 @@ import { IconButtonComponent } from '../../../../../../../../shared/components/i
})
export class TicketComponent {
readonly title = input('ENTRADA GENERAL');
readonly ticketId = input.required<string>();
readonly ticketId = input.required<string | number>();
readonly date = input<string | null>(null);
readonly disabled = input(false);
readonly expired = input(false);
readonly selected = model(false);
readonly viewQr = output<void>();

View File

@@ -33,8 +33,10 @@
@for (ticket of tickets(); track ticket.id) {
<app-ticket
[title]="ticket.name"
[ticketId]="ticket.ticket"
[ticketId]="ticket.id"
[date]="formatDate(ticket)"
[disabled]="!ticket.is_valid"
[expired]="ticket.is_expired"
[selected]="isSelected(ticket.id)"
(selectedChange)="toggleTicket(ticket.id, $event)"
/>