Files
frontend/src/app/pdf.service.ts
Piet Ostendorp a17c97e629 Add reservation code download feature
Introduces a download button in the reservation success component to allow users to download their reservation code as a text file. Adds utility methods in PdfService for downloading text and JSON files, and integrates the new download functionality into the component.
2025-11-26 12:40:49 +01:00

142 lines
4.3 KiB
TypeScript

import { Injectable, ComponentRef, ViewContainerRef, ApplicationRef, createComponent, EnvironmentInjector, inject, signal } from '@angular/core';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
import { Eintrittskarte } from '@infinimotion/model-frontend';
@Injectable({
providedIn: 'root',
})
export class PdfService {
private ticketsGreatedSignal = signal(0);
private totalTicketsSignal = signal(0);
readonly ticketsGreated = this.ticketsGreatedSignal.asReadonly();
readonly totalTickets = this.totalTicketsSignal.asReadonly();
appRef = inject(ApplicationRef);
injector = inject(EnvironmentInjector);
async genTicket(tickets: Eintrittskarte[], ticketComponent: any): Promise<void> {
if (tickets.length === 0) {
throw new Error('Keine Tickets zum Generieren vorhanden');
}
this.ticketsGreatedSignal.set(0)
this.totalTicketsSignal.set(tickets.length)
// Container für temporäres Rendering erstellen
const container = document.createElement('div');
container.style.position = 'fixed';
container.style.left = '-9999px';
container.style.top = '0';
document.body.appendChild(container);
const componentRefs: ComponentRef<any>[] = [];
try {
// Ticket-Format: 210mm x 99mm
const ticketWidthMM = 210;
const ticketHeightMM = 99;
const pdf = new jsPDF({
orientation: 'landscape',
unit: 'mm',
format: [ticketWidthMM, ticketHeightMM]
});
for (let i = 0; i < tickets.length; i++) {
const ticket = tickets[i];
// Komponente dynamisch erstellen
const componentRef = createComponent(ticketComponent, {
environmentInjector: this.injector
});
// Ticket-Daten an die Komponente übergeben
(componentRef.instance as any).ticket = ticket;
// Komponente ins DOM einfügen
this.appRef.attachView(componentRef.hostView);
container.appendChild(componentRef.location.nativeElement);
componentRefs.push(componentRef);
// Change Detection triggern
componentRef.changeDetectorRef.detectChanges();
// Kurz warten, damit alles gerendert ist
await new Promise(requestAnimationFrame);
// HTML zu Canvas konvertieren
const canvas = await html2canvas(componentRef.location.nativeElement, {
scale: 2,
backgroundColor: '#ffffff',
logging: false,
useCORS: true
});
const imgData = canvas.toDataURL('image/png');
if (i > 0) {
pdf.addPage([ticketWidthMM, ticketHeightMM], 'landscape');
}
// Bild ins PDF einfügen
pdf.addImage(imgData, 'PNG', 0, 0, ticketWidthMM, ticketHeightMM);
this.ticketsGreatedSignal.set(this.ticketsGreatedSignal() + 1)
}
const fileName = this.generateFileName(tickets);
pdf.save(fileName);
} catch (error) {
console.error('Fehler beim Generieren des PDFs:', error);
throw new Error('Das PDF konnte nicht erstellt werden. Bitte versuche es erneut.');
} finally {
componentRefs.forEach(ref => {
this.appRef.detachView(ref.hostView);
ref.destroy();
});
document.body.removeChild(container);
}
}
private generateFileName(tickets: Eintrittskarte[]): string {
const orderCode = tickets[0].order.code;
const timestamp = new Date().getTime();
return `Ticket_${orderCode}_${timestamp}.pdf`;
}
downloadTextFile(content: string, filename: string = 'textdatei.txt'): void {
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
downloadJsonFile(data: any, filename: string = 'data.json'): void {
const content = JSON.stringify(data, null, 2);
const blob = new Blob([content], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
}
}