Generer automatiquement un document

POUR CEUX QUI VEULENT GENERER UN DOCUMENT JE VAIS VOUS MONTRER COMMENT GENERER UN, TEXTE, UN TABLEAU ET UNE IMAGE MAIS JE NE VAIS QUE ME LIMITER AUX TROIS ENTITES.

//BACKEND COMMENT DECLENCHER UN TELECHARGEMENT AUTOMATIQUE ?

//FilmeName = AUTODownloading.jsw
   import { mediaManager } from "wix-media-backend";
import wixData from 'wix-data';


export function savePDF(base64, fileName) {
    return new Promise((resolve, reject) => {
        
        uploadPDF(base64, fileName)
            .then((file) => {

                getDownloadUrl(file.fileUrl)
                    .then((downloadUrl) => {
                        resolve(downloadUrl);
                    })
                    .catch((error) => {
                        reject(error);
                    });
            })
            .catch((error) => {
                reject(error);
            });
    });
}

export function uploadPDF(base64, fileName) {
    // create Buffer from Base64
    const buffer = Buffer.from(base64, 'base64');

    return mediaManager.upload(
        "/UserUploads",
        buffer,
        fileName + ".pdf", {
            "mediaOptions": {
                "mimeType": "application/pdf",
                "mediaType": "document"
            },
            "metadataOptions": {
                "isPrivate": false,
                "isVisitorUpload": false,
                "context": {
                    "someKey1": "someValue1",
                    "someKey2": "someValue2"
                }
            }
        }
    );
}

export async function getDownloadUrl(fileUrl) {
    const myFileDownloadUrl = await mediaManager.getDownloadUrl(fileUrl, 10);
    return myFileDownloadUrl;
}

2- TELECHARGER PDF-LIB VIA NPM

A-- CREER LE DOCUMENT DANS UN SEUL BOUTON nommé BOUTON4 DANS LE FRONTEND

import { savePDF } from "backend/AUTODownloading.jsw";
import wixData from 'wix-data';
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib';
$w('#button4').onClick(async()=>{
const pdfDoc = await PDFDocument.create();
const fileName = "MY DOCUMENT " + $w('#myTexte').text;
const PoliceFont = await pdfDoc.embedFont(StandardFonts.Helvetica);//Ma police préférée Helvetica 
const page = pdfDoc.addPage([600, 800]);
 const { width, height } = page.getSize();

Je tiens à préciser que je n’est pas fermé le bouton, le code n’est pas finit. TOUJOUR A L’INTERIEUR DU BOUTON, Voici le code de génération d’un Texte.

// A- Creer Texte
const fontSize9 = 15;
    page.drawText($w('#myText2').text;, {
        x: 400,
        y: height - 21 * fontSize,
        size: fontSize9,
        font: PoliceFont, //HELVETICA MA POLICE PREFERE
        color: rgb(0, 0, 0), //NOIR
    });

B- TOUJOURS A L’INTERIEUR DU MEME BOUTON, CODE POUR GENERER UN TABLEAU


const header = ['Prestations', 'Détails', "Achat (FCFA)", "Vente (FCFA)"]//CREER ENTETE DE TABLEAU (personnaliser le votre)
   
// Récupération des données
const results = await wixData
    .query("collectionName")
    .eq("fields1", $w('#text80').text)
    .eq('field2', "réponse devis")
    .find();


const tableDatas = results.items.map(item => ({
    prestation: item.Prestation || "N/A",
    detail: item.Détails || "N/A",
    achat: item.Achat || "N/A",
    vente: item.Vente || "N/A",
}));
//LES VALEURS N/A SONT LES VALEURS PAR DEFAUT (PAR DEFAUT EST LA MEILLEUR OPTION POUR RENDRE LA COLONNE RESPONSIVE)

const tableData = [header, ...tableDatas.map(data => [data.prestation, data.detail, data.achat, data.vente])] // FORMATER LES RESULTATS EN TABLEAU FORMAT WIX VALIDE

// Paramètres pour dessiner le tableau
const startX = 30;
let startY = 590; // Position de départ dynamique
const columnWidths = [120, 220, 100, 100]; // Largeur des colonnes
const defaultRowHeight = 40; // Hauteur minimale d'une ligne

// Fonction pour découper les textes trop longs en plusieurs lignes pour adapter les lignes en fonction du tableau
function splitTextToLines(text, columnWidth, fontSize, font) {
    const words = text.split(' ');
    let lines = [];
    let currentLine = '';

    words.forEach(word => {
        const testLine = currentLine ? `${currentLine} ${word}` : word;
        const testWidth = font.widthOfTextAtSize(testLine, fontSize);

        if (testWidth <= columnWidth) {
            currentLine = testLine;
        } else {
            lines.push(currentLine);
            currentLine = word;
        }
    });

    if (currentLine) lines.push(currentLine); // Ajouter la dernière ligne
    return lines;
}

// Dessiner le tableau avec bordures et texte inclus
tableData.forEach((row, rowIndex) => {
    let maxCellHeight = defaultRowHeight;

    // Calculer la hauteur dynamique de la ligne en fonction du texte le plus long
    const cellHeights = row.map((cell, colIndex) => {
        const lines = splitTextToLines(cell, columnWidths[colIndex], 15, timesRomanFont);
        return lines.length * 18; // 14 est la hauteur approximative d'une ligne (taille + espacement)
    });

    maxCellHeight = Math.max(...cellHeights);

    // Dessiner les cellules et le texte
    row.forEach((cell, colIndex) => {
        const x = startX + columnWidths.slice(0, colIndex).reduce((a, b) => a + b, 0);
        const y = startY;

        // Dessiner la bordure de la cellule
        page.drawRectangle({
            x: x,
            y: y - maxCellHeight, // Ajustement pour inclure toute la hauteur de la cellule
            width: columnWidths[colIndex],
            height: maxCellHeight,
            borderWidth: 1,
            borderColor: rgb(0, 0, 0), // Couleur noire pour les bordures
        });

        // Diviser le texte en lignes
        const fontSize = rowIndex === 0 ? 16 : 15; // Taille pour l'en-tête ou les lignes
        const lines = splitTextToLines(cell, columnWidths[colIndex], fontSize, timesRomanFont);

        // Dessiner chaque ligne de texte
        lines.forEach((line, lineIndex) => {
            const textX = x + 5; // Marge à gauche pour le texte
            const textY = y - 14 - lineIndex * (fontSize + 2); // Ajustement vertical pour chaque ligne

            page.drawText(line, {
                x: textX,
                y: textY,
                size: fontSize,
                font: timesRomanFont,
                color: rowIndex === 0 ? rgb(0, 0.53, 0.71) : rgb(0, 0, 0), // Couleur en-tête et lignes
            });
        });
    });

    // Réduire la position Y pour la prochaine ligne
    startY -= maxCellHeight;
});

C- GENERER DEUX (2) IMAGES (Image et Image1).


let baseUrl;
let cleanedUrl
let cleanedUrl1
let baseUrl1;
let image;
let image1;
let  imageBytes;
let  imageBytes1;
let extension;
let extension1;
const results1 = await wixData
    .query("CollectionName")
    .eq("_id", MyId)
    .find();
//console.log(results1.items[0].logo)

const wixImageUrl = results1.items[0].logo; // Votre URL Wix
const wixImageUrl1 = results1.items[0].image//URL de la seconde Image

if (wixImageUrl && wixImageUrl.startsWith("wix:image://v1/")) {
baseUrl = wixImageUrl.replace('wix:image://v1/', 'https://static.wixstatic.com/media/');
  
   cleanedUrl = baseUrl.replace(/(\.(jpg|jpeg|png|webp|avif|gif))[^\/]*.*/, '$1');
console.log(cleanedUrl)

}
else
{
   cleanedUrl = wixImageUrl 
}

if (wixImageUrl1 && wixImageUrl1.startsWith("wix:image://v1/")) {
baseUrl1 = wixImageUrl1.replace('wix:image://v1/', 'https://static.wixstatic.com/media/');
  
   cleanedUrl1 = baseUrl1.replace(/(\.(jpg|jpeg|png|webp|avif|gif))[^\/]*.*/, '$1');
console.log(cleanedUrl1)

}
else
{
   cleanedUrl1 = wixImageUrl1 
}

 extension = cleanedUrl.split('.').pop().toLowerCase();
 extension1 = cleanedUrl1.split('.').pop().toLowerCase();
        
       

//IL SE PEUT QUE l'URL NE SOIT PAS COMPATIBLE DONC FORMATER L'URL EN UNE EXTENSION WIX COMPATIBLE

    imageBytes = await fetch(cleanedUrl).then((res) => res.arrayBuffer());
 if (['png'].includes(extension)) {
            image = await pdfDoc.embedPng(imageBytes);
        } else if (['jpg', 'jpeg'].includes(extension)) {
            image = await pdfDoc.embedJpg(imageBytes);
        } else {
            $w('#box67').show()
        }
        
         imageBytes1 = await fetch(cleanedUrl1).then((res) => res.arrayBuffer());
 if (['png'].includes(extension1)) {
            image1 = await pdfDoc.embedPng(imageBytes1);
        } else if (['jpg', 'jpeg'].includes(extension1)) {
            image1 = await pdfDoc.embedJpg(imageBytes1);
        } else {
            console.error("une erreur s'est produite soit parce que votre URL d'image est undefined (recherche query à échoué), soit à cause de l'extension de votre image verifiez s'il est jpg, jpeg ou png")
        }
// Taille et position de l'image
const imageWidth = 200; // Largeur de l'image
const imageHeight = 100; // Hauteur de l'image
const imageX = 33; // Position X de l'image
const imageY = 750; // Position Y de l'image

// Dessiner l'image
page.drawImage(image, {
    x: imageX,
    y: imageY,
    width: imageWidth,
    height: imageHeight,
});


const imageWidth1 = 200; // Largeur de l'image
const imageHeight1 = 100; // Hauteur de l'image
const imageX1 = 300; // Position X de l'image
const imageY1 = 200; // Position Y de l'image

// Dessiner la 2e l'image
page.drawImage(image1, {
    x: imageX1,
    y: imageY1,
    width: imageWidth1,
    height: imageHeight1,
});

ETAPE FINALE TOUJOURS DANS LE MEME BOUTON DECLENCHER LE TELECHARGEMENT ET GENERER L’URL.

// Generer le PDF
// Sauvegarder et télécharger le PDF
const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
const dataUriPrefix = 'data:application/pdf;base64,';
const base64 = pdfDataUri.slice(dataUriPrefix.length);

savePDF(base64, fileName)
    .then(downloadUrl => {
        console.log(downloadUrl);
        wixLocation.to(downloadUrl); // Fonctionne uniquement en ligne
    })
    .catch((error) => {
        console.error("Error while saving the PDF: ", error);
    });
})//IL FAUT FERMER LE BOUTON

NORMALEMENT LE CODE EST TERMINE ET CELA FONCTIONNE CHEZ MOI

IMPORTANT : cet URL Généré n’est disponible que 1 heure, si vous voulez enregistrer le pdf definitivement dans votre collection alors vous suivez le tuto :

Wix-fetch reponse.blob// enregistrer automatiquement n’importe quel document dans sa collection - Show and tell - Community Support Forum | Wix Studio