feat(ticket): enhance ticket component with disabled and expired states, update styles and tests
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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)"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user