Cours Vibe coding avec l'IA · Module 8: Clone de Slack
Export de données - rapports CSV et PDF
Dans cette leçon2
Le tableau de bord est superbe, mais le quartier-maître veut les chiffres dans un tableur, et l'armateur un rapport en PDF. Plutôt que de tout recopier à la main, ajoutons deux boutons : Export CSV et Export PDF. Les deux fichiers naîtront dans le navigateur, sans passer par le serveur.
L'export en CSV
Le CSV est du texte brut : la première ligne contient les en-têtes, chaque ligne suivante un enregistrement aux valeurs séparées par des virgules. exportToCSV construit ce texte et le fait télécharger par le navigateur, et DataTable l'appelle avec un bouton :
1function exportToCSV(data: any[], filename: string) {
2 const headers = Object.keys(data[0]).join(',');
3 const rows = data.map(row => Object.values(row).join(','));
4 const csv = [headers, ...rows].join('\n');
5
6 const blob = new Blob([csv], { type: 'text/csv' });
7 const url = URL.createObjectURL(blob);
8 const link = document.createElement('a');
9 link.href = url;
10 link.download = filename;
11 link.click();
12}
13
14function DataTable({ data }: { data: any[] }) {
15 return (
16 <div>
17 <button
18 onClick={() => exportToCSV(data, 'report.csv')}
19 className="bg-green-600 text-white px-4 py-2 rounded mb-4"
20 >
21 Export CSV
22 </button>
23 <table className="w-full border">
24 {/* Contenu du tableau */}
25 </table>
26 </div>
27 );
28}Quatre étapes. Object.keys(data[0]).join(',') crée la ligne d'en-têtes à partir des clés du premier objet, Object.values(row).join(',') fait de même avec les valeurs, et un saut de ligne relie le tout (join('\n')). Puis naît un Blob de type text/csv, un fichier gardé en mémoire par le navigateur. URL.createObjectURL(blob) lui donne une adresse temporaire, et link.download = filename puis link.click() lancent le téléchargement de report.csv. Les données du tableau restent inchangées. Ce schéma télécharge tout fichier construit dans le navigateur, du JSON par exemple.
En production, trois corrections aident. Une valeur avec virgule, guillemet ou saut de ligne casse les colonnes : entoure-la de guillemets et double chaque guillemet intérieur, comme l'exige le standard CSV :
1const escapeCell = (value: unknown) => `"${String(value).replace(/"/g, '""')}"`;La fonction renvoie un nouveau texte de cellule et ne touche pas à la valeur d'origine. Après le téléchargement, libère l'adresse avec URL.revokeObjectURL(url), et dès le début vérifie data.length, car un tableau vide fait planter la fonction sur data[0].
L'export en PDF
jsPDF générera le PDF, et son extension jspdf-autotable dessinera le tableau. Tu les installes ensemble, et la commande seule ne modifie encore aucun composant :
1npm install jspdf jspdf-autotableAprès l'installation, l'export tient en quelques lignes : tu crées un document, écris un titre, dessines un tableau et enregistres le fichier.
1import jsPDF from 'jspdf';
2import autoTable from 'jspdf-autotable';
3
4function exportToPDF(data: any[], filename: string) {
5 const doc = new jsPDF();
6
7 doc.text('Analytics Report', 14, 15);
8
9 autoTable(doc, {
10 head: [Object.keys(data[0])],
11 body: data.map(row => Object.values(row))
12 });
13
14 doc.save(filename);
15}new jsPDF() crée un document, A4 en millimètres par défaut. doc.text('Analytics Report', 14, 15) écrit le titre à 14 mm du bord gauche et 15 mm du haut, et autoTable dessine un tableau avec les en-têtes (head) et les lignes (body). head est un tableau de lignes d'en-tête, d'où les doubles crochets autour de Object.keys(data[0]), et body contient un tableau de valeurs par enregistrement. doc.save(filename) télécharge le fichier terminé, et le tableau de la page reste inchangé. Les polices PDF standard ne couvrent qu'un jeu de caractères limité : pour des lettres comme ą ou ł, ajoute ta propre police TTF. Lance l'export côté client, par exemple dans onClick : le téléchargement a lieu dans le navigateur.
Conseil du Capitaine Barbe-Rouge : un tableur peut prendre une valeur commençant par =, +, - ou @ pour une formule. Pour des données saisies par les utilisateurs, préfixe ces valeurs d'une apostrophe, pour que personne ne glisse de formule dans ta cargaison.
À retenir : le CSV, c'est du texte dans un Blob, le PDF un document jsPDF, et tous deux arrivent à l'utilisateur par un téléchargement. Dans l'éditeur ci-dessous, tu as un rapport de canal avec un export CSV, et les exercices porteront sur les étapes de l'export.
Code de cette leçon : App.jsx
1// Export de données - téléchargement CSV
2import { useState } from 'react';
3
4const reportData = [
5 { canal: 'treasure-hunts', messages: 142, membres: 8 },
6 { canal: 'general', messages: 89, membres: 12 },
7 { canal: 'navigation', messages: 56, membres: 5 }
8];
9
10function exportToCSV(data, filename) {
11 const headers = Object.keys(data[0]).join(',');
12 const rows = data.map(row => Object.values(row).join(','));
13 const csv = [headers, ...rows].join('\n');
14
15 const blob = new Blob([csv], { type: 'text/csv' });
16 const url = URL.createObjectURL(blob);
17 const link = document.createElement('a');
18 link.href = url;
19 link.download = filename;
20 link.click();
21}
22
23export default function App() {
24 return (
25 <div className="min-h-screen bg-gray-100 p-8">
26 <div className="max-w-3xl mx-auto bg-white border rounded p-6">
27 <div className="flex items-center justify-between mb-4">
28 <h1 className="text-xl font-bold">Rapport du canal</h1>
29 <button
30 onClick={() => exportToCSV(reportData, 'rapport.csv')}
31 className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 text-sm font-semibold"
32 >
33 Exporter en CSV
34 </button>
35 </div>
36
37 <table className="w-full border text-left text-sm">
38 <thead className="bg-gray-50">
39 <tr>
40 {Object.keys(reportData[0]).map(key => (
41 <th key={key} className="border px-3 py-2 font-semibold">{key}</th>
42 ))}
43 </tr>
44 </thead>
45 <tbody>
46 {reportData.map((row, idx) => (
47 <tr key={idx}>
48 {Object.values(row).map((val, i) => (
49 <td key={i} className="border px-3 py-2">{val}</td>
50 ))}
51 </tr>
52 ))}
53 </tbody>
54 </table>
55 </div>
56 </div>
57 );
58}Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Quel type MIME définit-on dans le Blob lors de l'export CSV ?
2. Comment crée-t-on la ligne d'en-tête CSV à partir d'un objet de données ?
Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Éditeur de code
Exporter des données vers un fichier CSV
- Tri vertical
Ordonne les étapes pour télécharger un fichier CSV dans le navigateur :