couveo · TM1
// GÉNÉRATEUR NATTIF VECTORIEL VIA JSPDF const handleDownloadPDF = (b: any) => { setIsGeneratingPDF(true); // Fait clignoter "Génération..." — TM1
// GÉNÉRATEUR NATTIF VECTORIEL VIA JSPDF
const handleDownloadPDF = (b: any) => { setIsGeneratingPDF(true); // Fait clignoter "Génération..." sur le bouton // Nom du fichier sécurisé (remplace les espaces et accents par des tirets du bas) const safeEventName = b.event_name ? b.event_name.replace(/[^a-zA-Z0-9À-ÿ]/g, '_') : 'Event'; // 1. Import des librairies depuis un CDN (pour ne pas alourdir ton app) const loadScript = (src: string) => { return new Promise((resolve, reject) => { if (document.querySelector(`script[src="${src}"]`)) { resolve(true); return; } const script = document.createElement('script'); script.src = src; script.onload = () => resolve(true); script.onerror = (err) => reject(err); document.body.appendChild(script); }); }; // Chargement de jsPDF puis de AutoTable loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js') .then(() => loadScript('https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.31/jspdf.plugin.autotable. min.js')) .then(() => { // @ts-ignore const { jsPDF } = window.jspdf; const doc = new jsPDF(); // Création du document A4 Vierge // Fonction pour éviter que la mention "undefined" apparaisse dans le PDF const safeVal = (v: any) => (v !== undefined && v !== null && v !== '') ? String(v) : ' '; // Titre Principal doc.setFontSize(16); doc.setFont("helvetica", "bold"); doc.text("FICHE DE RENSEIGNEMENTS", 105, 20, { align: "center" }); let currentY = 30; // Curseur de hauteur (on commence à 30mm du haut) // 2. Le moteur de création de Section (Gris + Titre + Tableau) const addSection = (title: string, data: any[][], head?: any[][]) => { // Dessin du rectangle Gris clair de la section doc.setFillColor(244, 244, 244); doc.rect(14, currentY, 182, 8, "F"); // Dessin du mini liseré Noir sur la gauche du rectangle doc.setFillColor(0, 0, 0); doc.rect(14, currentY, 2, 8, "F"); // Ajout du Titre de la section doc.setFontSize(11); doc.setFont("helvetica", "bold"); doc.setTextColor(0, 0, 0); doc.text(title, 19, currentY + 5.5); currentY += 10; // Génération du tableau avec AutoTable // @ts-ignore doc.autoTable({ startY: currentY, head: head || [], body: data, theme: 'grid', styles: { font: 'helvetica', fontSize: 10, textColor: [0, 0, 0], lineColor: [200, 200, 200], lineWidth: 0.1, cellPadding: 3 }, headStyles: { fillColor: [244, 244, 244], textColor: [0, 0, 0], fontStyle: 'bold' }, columnStyles: head ? {} : { 0: { cellWidth: 70, fontStyle: 'bold' }, 1: { cellWidth: 'auto' } }, // La colonne 1 fait 70mm, l'autre prend le reste margin: { left: 14, right: 14 } }); // @ts-ignore currentY = doc.lastAutoTable.finalY + 10; // On descend le curseur après le tableau // Si on s'approche trop du bas de page, on crée une nouvelle page ! if (currentY > 260) { doc.addPage(); currentY = 20; } }; // Formatages spéciaux (dates et monnaies) const dateStr = b.event_date ? new Date(b.event_date).toLocaleDateString('fr-FR') : ' '; const cCession = b.fee_gross ? fmt(cleanNum(b.fee_gross)) + ' ¬' : ' '; const cVhr = b.transport_gross ? fmt(cleanNum(b.transport_gross)) + ' ¬' : ' '; const totalNum = cleanNum(b.fee_gross) + cleanNum(b.transport_gross); const total = totalNum > 0 ? fmt(totalNum) + ' ¬' : ' '; // 3. Appel de la fonction pour chaque section addSection("ARTISTE", [ ["ARTISTE :", safeVal(b.artist_name)], ["DATE CONCERT :", dateStr], ["TARIF CESSION HT (TVA 5,5%) :", cCession], ["VHR HT (TVA 5,5%) :", cVhr], ["TOTAL CESSION + VHR HT (TVA 5,5%) :", total] ]); addSection("ÉLÉMENTS ADMINISTRATIFS", [ ["Structure signataire :", safeVal(b.signing_organization)], ["Adresse :", safeVal(b.address)], ["N° SIRET / N° RNA :", safeVal(b.business_registration_number)], ["Code APE :", safeVal(b.sic_code)], ["N° de licence :", safeVal(b.entertainment_licence_number)], ["N°TVA intracommunautaire :", safeVal(b.vat_number)], ["Signataire :", safeVal(b.name_on_the_contract)], ["En qualité de :", safeVal(b.acting_as)] ]); addSection("SALLE OU LIEU", [ ["Nom soirée / festival / lieu :", safeVal(b.event_name)], ["Tournée :", safeVal(b.tour_name)], ["Nom de la salle / scène :", safeVal(b.stage_name)], ["Adresse :", safeVal(b.event_address)], ["Heure du spectacle (Set Time) :", safeVal(b.set_time)], ["Durée du set :", safeVal(b.set_length)], ["Capacité d'accueil (jauge) :", safeVal(b.capacity)], ["Prix du billet :", b.ticket_price ? b.ticket_price + ' ¬' : ' '], ["Line Up :", safeVal(b.line_up)] ]); addSection("CONTACTS", [ ["Contact Administration", safeVal(b.admin_contact_name), safeVal(b.admin_contact_phone), safeVal(b.admin_contact_email)], ["Contact Programmation", safeVal(b.prog_contact_name), safeVal(b.prog_contact_phone), safeVal(b.prog_contact_email)], ["Contact Régie", safeVal(b.regie_contact_name), safeVal(b.regie_contact_phone), safeVal(b.regie_contact_email)] ], [["Fonction", "Prénom + NOM", "N° Tel Portable", "Adresse e-mail"]]); // Tableau à 4 colonnes addSection("HÉBERGEMENT & LOGISTIQUE", [ ["Heure Soundcheck :", safeVal(b.soundcheck_time)], ["Heure Déjeuner :", safeVal(b.lunch_time)], ["Point de rendez-vous :", safeVal(b.meeting_point)], ["Aéroport / Gare :", safeVal(b.nearest_airport_station)], ["Détails du voyage :", safeVal(b.travel_details)], ["Temps de transfert hôtel :", safeVal(b.transfer_time_to_hotel)], ["Hôtel 4* requis :", b.hotel_4_star ? 'OUI' : (b.hotel_4_star === false ? 'NON' : ' ')], ["Nom de l'hôtel :", safeVal(b.hotel_name)], ["Adresse de l'hôtel :", safeVal(b.hotel_address)], ["Heure de départ (Checkout) :", safeVal(b.hotel_checkout)] ]); // 4. Lancement du téléchargement doc.save(`Fiche_Renseignements_${safeEventName}.pdf`); setIsGeneratingPDF(false); }) .catch(err => { console.error('Erreur PDF:', err); alert("Erreur lors de la génération du PDF. Vérifiez votre connexion internet."); setIsGeneratingPDF(false); }); };